Skip to main content

packet_formats/ipv6/
mod.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Parsing and serialization of IPv6 packets.
6//!
7//! The IPv6 packet format is defined in [RFC 8200] Sections 3 and 4.
8//!
9//! [RFC 8200]: https://datatracker.ietf.org/doc/html/rfc8200
10
11pub mod ext_hdrs;
12
13use alloc::vec::Vec;
14use core::borrow::Borrow;
15use core::fmt::{self, Debug, Formatter};
16use core::ops::Range;
17
18use log::debug;
19use net_types::ip::{GenericOverIp, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr};
20use packet::records::{AlignedRecordSequenceBuilder, Records, RecordsRaw};
21use packet::{
22    BufferProvider, BufferView, BufferViewMut, EmptyBuf, FragmentedBytesMut, FromRaw,
23    GrowBufferMut, InnerPacketBuilder, LayoutBufferAlloc, MaybeParsed, NestablePacketBuilder,
24    NestableSerializer, NoOpSerializationContext, PacketBuilder, PacketConstraints, ParsablePacket,
25    ParseMetadata, PartialPacketBuilder, PartialSerializer, SerializeError, SerializeTarget,
26    Serializer,
27};
28use zerocopy::byteorder::network_endian::{U16, U32};
29use zerocopy::{
30    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
31};
32
33use crate::TRANSPORT_HEADER_MAX_SIZE;
34use crate::error::{IpParseErrorAction, IpParseResult, Ipv6ParseError, ParseError};
35use crate::icmp::Icmpv6ParameterProblemCode;
36use crate::ip::{
37    DscpAndEcn, FragmentOffset, IpEnvelope, IpExt, IpPacketBuilder, IpProto,
38    IpSerializationContext, Ipv4Proto, Ipv6ExtHdrType, Ipv6Proto, Nat64Error,
39    Nat64TranslationResult,
40};
41use crate::ipv4::{HDR_PREFIX_LEN, Ipv4PacketBuilder};
42use crate::ipv6::ext_hdrs::ExtensionHeaderOptionAction;
43use crate::tcp::{TcpParseArgs, TcpSegment};
44use crate::udp::{UdpPacket, UdpParseArgs};
45
46use ext_hdrs::{
47    HopByHopOption, HopByHopOptionData, IPV6_FRAGMENT_EXT_HDR_LEN, Ipv6ExtensionHeader,
48    Ipv6ExtensionHeaderImpl, Ipv6ExtensionHeaderParsingContext, Ipv6ExtensionHeaderParsingError,
49    is_valid_next_header_upper_layer,
50};
51
52/// Length of the IPv6 fixed header.
53pub const IPV6_FIXED_HDR_LEN: usize = 40;
54
55/// The range of bytes within an IPv6 header buffer that the
56/// payload length field uses.
57pub const IPV6_PAYLOAD_LEN_BYTE_RANGE: Range<usize> = 4..6;
58
59// Offset to the Next Header field within the fixed IPv6 header
60const NEXT_HEADER_OFFSET: u8 = 6;
61
62// The maximum length for Hop-by-Hop Options. The stored byte's maximum
63// representable value is `core::u8::MAX` and it means the header has
64// that many 8-octets, not including the first 8 octets.
65const IPV6_HBH_OPTIONS_MAX_LEN: usize = (core::u8::MAX as usize) * 8 + 8;
66
67/// The maximum payload length after an IPv6 header.
68///
69/// The maximum IPv6 payload is the total number of bytes after the fixed header
70/// and must fit in a u16 as defined in [RFC 8200 Section 3].
71///
72/// [RFC 8200 Section 3]: https://datatracker.ietf.org/doc/html/rfc8200#section-3.
73const IPV6_MAX_PAYLOAD_LENGTH: usize = core::u16::MAX as usize;
74
75/// Convert an extension header parsing error to an IP packet
76/// parsing error.
77fn ext_hdr_err_fn(hdr: &FixedHeader, err: Ipv6ExtensionHeaderParsingError) -> Ipv6ParseError {
78    // Below, we set parameter problem data's `pointer` to `IPV6_FIXED_HDR_LEN` + `pointer`
79    // since the the `pointer` we get from an `Ipv6ExtensionHeaderParsingError` is calculated
80    // from the start of the extension headers. Within an IPv6 packet, extension headers
81    // start right after the fixed header with a length of `IPV6_FIXED_HDR_LEN` so we add `pointer`
82    // to `IPV6_FIXED_HDR_LEN` to get the pointer to the field with the parameter problem error
83    // from the start of the IPv6 packet. For a non-jumbogram packet, we know that
84    // `IPV6_FIXED_HDR_LEN` + `pointer` will not overflow because the maximum size of an
85    // IPv6 packet is 65575 bytes (fixed header + extension headers + body) and 65575 definitely
86    // fits within an `u32`. This may no longer hold true if/when jumbogram packets are supported.
87    // For the jumbogram case when the size of extension headers could be >= (4 GB - 41 bytes) (which
88    // we almost certainly will never encounter), the pointer calculation may overflow. To account for
89    // this scenario, we check for overflows when adding `IPV6_FIXED_HDR_LEN` to `pointer`. If
90    // we do end up overflowing, we will discard the packet (even if we were normally required to
91    // send back an ICMP error message) because we will be unable to construct a correct ICMP error
92    // message (the pointer field of the ICMP message will not be able to hold a value > (4^32 - 1)
93    // which is what we would have if the pointer calculation overflows). But again, we should almost
94    // never encounter this scenario so we don't care if we have incorrect behaviour.
95
96    match err {
97        Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } => {
98            Ipv6ParseError::ParameterProblem {
99                src_ip: hdr.src_ip,
100                dst_ip: hdr.dst_ip,
101                code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
102                pointer,
103                must_send_icmp,
104                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
105            }
106        }
107        Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } => {
108            Ipv6ParseError::ParameterProblem {
109                src_ip: hdr.src_ip,
110                dst_ip: hdr.dst_ip,
111                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
112                pointer,
113                must_send_icmp,
114                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
115            }
116        }
117        Ipv6ExtensionHeaderParsingError::UnrecognizedOption { pointer, must_send_icmp, action } => {
118            let action = match action {
119                ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
120                    "Should never end up here because this action should never result in an error"
121                ),
122                ExtensionHeaderOptionAction::DiscardPacket => IpParseErrorAction::DiscardPacket,
123                ExtensionHeaderOptionAction::DiscardPacketSendIcmp => {
124                    IpParseErrorAction::DiscardPacketSendIcmp
125                }
126                ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => {
127                    IpParseErrorAction::DiscardPacketSendIcmpNoMulticast
128                }
129            };
130
131            Ipv6ParseError::ParameterProblem {
132                src_ip: hdr.src_ip,
133                dst_ip: hdr.dst_ip,
134                code: Icmpv6ParameterProblemCode::UnrecognizedIpv6Option,
135                pointer,
136                must_send_icmp,
137                action,
138            }
139        }
140        Ipv6ExtensionHeaderParsingError::BufferExhausted
141        | Ipv6ExtensionHeaderParsingError::MalformedData => {
142            // Unexpectedly running out of a buffer or encountering malformed
143            // data when parsing is a formatting error.
144            Ipv6ParseError::Parse { error: ParseError::Format }
145        }
146    }
147}
148
149/// The IPv6 fixed header which precedes any extension headers and the body.
150#[derive(Debug, Default, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq)]
151#[repr(C)]
152pub struct FixedHeader {
153    version_tc_flowlabel: [u8; 4],
154    payload_len: U16,
155    next_hdr: u8,
156    hop_limit: u8,
157    src_ip: Ipv6Addr,
158    dst_ip: Ipv6Addr,
159}
160
161const IP_VERSION: u8 = 6;
162const VERSION_OFFSET: u8 = 4;
163const FLOW_LABEL_MAX: u32 = (1 << 20) - 1;
164
165impl FixedHeader {
166    #[allow(clippy::too_many_arguments)]
167    fn new(
168        dscp_and_ecn: DscpAndEcn,
169        flow_label: u32,
170        payload_len: u16,
171        next_hdr: u8,
172        hop_limit: u8,
173        src_ip: Ipv6Addr,
174        dst_ip: Ipv6Addr,
175    ) -> FixedHeader {
176        debug_assert!(flow_label <= FLOW_LABEL_MAX);
177
178        let traffic_class = dscp_and_ecn.raw();
179        FixedHeader {
180            version_tc_flowlabel: [
181                IP_VERSION << VERSION_OFFSET | traffic_class >> 4,
182                (traffic_class << 4) | ((flow_label >> 16) as u8),
183                (flow_label >> 8) as u8,
184                flow_label as u8,
185            ],
186            payload_len: U16::new(payload_len),
187            next_hdr,
188            hop_limit,
189            src_ip,
190            dst_ip,
191        }
192    }
193
194    fn version(&self) -> u8 {
195        self.version_tc_flowlabel[0] >> 4
196    }
197
198    fn dscp_and_ecn(&self) -> DscpAndEcn {
199        ((self.version_tc_flowlabel[0] & 0xF) << 4 | self.version_tc_flowlabel[1] >> 4).into()
200    }
201
202    fn flowlabel(&self) -> u32 {
203        (u32::from(self.version_tc_flowlabel[1]) & 0xF) << 16
204            | u32::from(self.version_tc_flowlabel[2]) << 8
205            | u32::from(self.version_tc_flowlabel[3])
206    }
207}
208
209/// Provides common access to IPv6 header fields.
210///
211/// `Ipv6Header` provides access to IPv6 header fields as a common
212/// implementation for both [`Ipv6Packet`] and [`Ipv6PacketRaw`].
213pub trait Ipv6Header {
214    /// Gets a reference to the IPv6 [`FixedHeader`].
215    fn get_fixed_header(&self) -> &FixedHeader;
216
217    /// The Hop Limit.
218    fn hop_limit(&self) -> u8 {
219        self.get_fixed_header().hop_limit
220    }
221
222    /// The Next Header.
223    fn next_header(&self) -> u8 {
224        self.get_fixed_header().next_hdr
225    }
226
227    /// The source IP address.
228    fn src_ip(&self) -> Ipv6Addr {
229        self.get_fixed_header().src_ip
230    }
231
232    /// The destination IP address.
233    fn dst_ip(&self) -> Ipv6Addr {
234        self.get_fixed_header().dst_ip
235    }
236
237    /// The Differentiated Services Code Point (DSCP) and the Explicit
238    /// Congestion Notification (ECN).
239    fn dscp_and_ecn(&self) -> DscpAndEcn {
240        self.get_fixed_header().dscp_and_ecn()
241    }
242}
243
244impl Ipv6Header for FixedHeader {
245    fn get_fixed_header(&self) -> &FixedHeader {
246        self
247    }
248}
249
250/// An IPv6 packet.
251///
252/// An `Ipv6Packet` shares its underlying memory with the byte slice it was
253/// parsed from or serialized to, meaning that no copying or extra allocation is
254/// necessary.
255pub struct Ipv6Packet<B> {
256    fixed_hdr: Ref<B, FixedHeader>,
257    extension_hdrs: Records<B, Ipv6ExtensionHeaderImpl>,
258    body: B,
259    proto: Ipv6Proto,
260}
261
262impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv6Packet<B> {
263    type Type = <I as IpExt>::Packet<B>;
264}
265
266impl<B: SplitByteSlice> Ipv6Header for Ipv6Packet<B> {
267    fn get_fixed_header(&self) -> &FixedHeader {
268        &self.fixed_hdr
269    }
270}
271
272impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv6Packet<B> {
273    type Error = Ipv6ParseError;
274
275    fn parse_metadata(&self) -> ParseMetadata {
276        let header_len = Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.bytes().len();
277        ParseMetadata::from_packet(header_len, self.body.len(), 0)
278    }
279
280    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, Ipv6ParseError> {
281        Ipv6PacketRaw::parse(buffer, ()).and_then(Ipv6Packet::try_from_raw)
282    }
283}
284
285impl<B: SplitByteSlice> FromRaw<Ipv6PacketRaw<B>, ()> for Ipv6Packet<B> {
286    type Error = Ipv6ParseError;
287
288    fn try_from_raw_with(raw: Ipv6PacketRaw<B>, _args: ()) -> Result<Self, Self::Error> {
289        let fixed_hdr = raw.fixed_hdr;
290
291        let extension_hdrs = match raw.extension_hdrs {
292            MaybeParsed::Complete(v) => Records::try_from_raw(v),
293            MaybeParsed::Incomplete(buffer) => {
294                // If raw parser failed then try full parser again. This is
295                // expected to fail, but the returned error may be different
296                // from the error reported by the raw parser.
297                let context = Ipv6ExtensionHeaderParsingContext::new(fixed_hdr.next_hdr);
298                match Records::<_, Ipv6ExtensionHeaderImpl>::parse_with_context(buffer, context) {
299                    Err(err) => Err(err),
300                    Ok(_) => panic!("Extension Header parsing succeeded after raw parse failure."),
301                }
302            }
303        };
304        let extension_hdrs = extension_hdrs.map_err(|e| ext_hdr_err_fn(&fixed_hdr, e))?;
305
306        // If extension headers parse successfully, then proto and a
307        // `MaybeParsed` body MUST be available, and the proto must be a valid
308        // next header for upper layers.
309        let (body, proto) =
310            raw.body_proto.expect("Unable to retrieve Ipv6Proto or MaybeParsed body from raw");
311        debug_assert!(is_valid_next_header_upper_layer(proto.into()));
312
313        let body = match body {
314            MaybeParsed::Complete(b) => b,
315            MaybeParsed::Incomplete(_b) => {
316                return debug_err!(Err(ParseError::Format.into()), "IPv6 body unretrievable.");
317            }
318        };
319
320        // check that the lengths match:
321        //
322        // As per Section 3 of RFC 8200, payload length includes the length of
323        // the extension headers as well.
324        if extension_hdrs.bytes().len() + body.len() != usize::from(fixed_hdr.payload_len.get()) {
325            return debug_err!(
326                Err(ParseError::Format.into()),
327                "Payload len does not match body and extension headers"
328            );
329        }
330
331        // validate IP version in header
332        if fixed_hdr.version() != 6 {
333            return debug_err!(
334                Err(ParseError::Format.into()),
335                "unexpected IP version: {}",
336                fixed_hdr.version()
337            );
338        }
339
340        Ok(Ipv6Packet { fixed_hdr, extension_hdrs, body, proto })
341    }
342}
343
344impl<B, C> PartialSerializer<C> for Ipv6Packet<B>
345where
346    B: SplitByteSlice,
347    C: IpSerializationContext<Ipv6>,
348{
349    // TODO(https://fxbug.dev/473824085): Keep the reference to the whole
350    // serialized packet and return it from `partial_serialize()` as
351    // `PartialSerializeResult::Slice`.
352
353    fn partial_serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
354        &self,
355        _context: &mut C,
356        constraints: PacketConstraints,
357        alloc: A,
358    ) -> Result<(BB, usize), SerializeError<A::Error>> {
359        // Copy IP header, extension header and up to 64 bytes of the body,
360        // which includes the transport headers.
361        let fixed_hdr = Ref::bytes(&self.fixed_hdr);
362        let extension_hdrs = self.extension_hdrs.bytes();
363        let fixed_hdr_len = fixed_hdr.len();
364        let header_len = fixed_hdr_len + extension_hdrs.len();
365        let body_to_copy = self.body().len().min(TRANSPORT_HEADER_MAX_SIZE);
366        let outer_header_len = constraints.header_len();
367        let mut buffer = alloc.layout_alloc(outer_header_len + header_len, body_to_copy, 0)?;
368        buffer.with_parts_mut(|prefix, mut body, _suffix| {
369            let extensions_pos = outer_header_len + fixed_hdr_len;
370            prefix[outer_header_len..extensions_pos].copy_from_slice(fixed_hdr);
371            prefix[extensions_pos..].copy_from_slice(extension_hdrs);
372            body.copy_from_slice(&self.body()[..body_to_copy]);
373        });
374        buffer.grow_front(header_len);
375        let total_size = header_len + self.body.len();
376        Ok((buffer, total_size))
377    }
378}
379
380impl<B: SplitByteSlice> Ipv6Packet<B> {
381    /// Returns an iterator over the extension headers.
382    pub fn iter_extension_hdrs(&self) -> impl Iterator<Item = Ipv6ExtensionHeader<'_>> {
383        self.extension_hdrs.iter()
384    }
385
386    /// The packet body.
387    pub fn body(&self) -> &[u8] {
388        &self.body
389    }
390
391    /// The Differentiated Services Code Point (DSCP) and the Explicit
392    /// Congestion Notification (ECN).
393    pub fn dscp_and_ecn(&self) -> DscpAndEcn {
394        self.fixed_hdr.dscp_and_ecn()
395    }
396
397    /// The flow label.
398    pub fn flowlabel(&self) -> u32 {
399        self.fixed_hdr.flowlabel()
400    }
401
402    /// The Upper layer protocol for this packet.
403    ///
404    /// This is found in the fixed header's Next Header if there are no extension
405    /// headers, or the Next Header value in the last extension header if there are.
406    /// This also  uses the same codes, encoded by the Rust type `Ipv6Proto`.
407    pub fn proto(&self) -> Ipv6Proto {
408        self.proto
409    }
410
411    /// The source IP address represented as an [`Ipv6SourceAddr`].
412    ///
413    /// Unlike [`IpHeader::src_ip`], `src_ipv6` returns an `Ipv6SourceAddr`,
414    /// which represents the valid values that a source address can take
415    /// (namely, a unicast or unspecified address) or `None` if the address is
416    /// invalid (namely, a multicast address or an ipv4-mapped-ipv6 address).
417    pub fn src_ipv6(&self) -> Option<Ipv6SourceAddr> {
418        Ipv6SourceAddr::new(self.fixed_hdr.src_ip)
419    }
420
421    /// Return a buffer that is a copy of the header bytes in this
422    /// packet, including the fixed and extension headers, but without
423    /// the first fragment extension header.
424    ///
425    /// Note, if there are multiple fragment extension headers, only
426    /// the first fragment extension header will be removed.
427    ///
428    /// # Panics
429    ///
430    /// Panics if there is no fragment extension header in this packet.
431    pub fn copy_header_bytes_for_fragment(&self) -> Vec<u8> {
432        // Since the final header will not include a fragment header, we don't
433        // need to allocate bytes for it (`IPV6_FRAGMENT_EXT_HDR_LEN` bytes).
434        let expected_bytes_len = self.header_len() - IPV6_FRAGMENT_EXT_HDR_LEN;
435        let mut bytes = Vec::with_capacity(expected_bytes_len);
436
437        bytes.extend_from_slice(Ref::bytes(&self.fixed_hdr));
438
439        // We cannot simply copy over the extension headers because we want
440        // discard the first fragment header, so we iterate over our
441        // extension headers and find out where our fragment header starts at.
442        let mut iter = self.extension_hdrs.iter();
443
444        // This should never panic because we must only call this function
445        // when the packet is fragmented so it must have at least one extension
446        // header (the fragment extension header).
447        let ext_hdr = iter.next().expect("packet must have at least one extension header");
448
449        if self.fixed_hdr.next_hdr == Ipv6ExtHdrType::Fragment.into() {
450            // The fragment header is the first extension header so
451            // we need to patch the fixed header.
452
453            // Update the next header value in the fixed header within the buffer
454            // to the next header value from the fragment header.
455            bytes[6] = iter.context().next_header;
456
457            // Copy extension headers that appear after the fragment header
458            bytes.extend_from_slice(&self.extension_hdrs.bytes()[IPV6_FRAGMENT_EXT_HDR_LEN..]);
459        } else {
460            let mut ext_hdr = ext_hdr;
461            let mut ext_hdr_start = IPV6_FIXED_HDR_LEN;
462            let mut ext_hdr_end = iter.context().position;
463
464            // Here we keep looping until `next_ext_hdr` points to the fragment header.
465            // Once we find the fragment header, we update the next header value within
466            // the extension header preceeding the fragment header, `ext_hdr`. Note,
467            // we keep track of where in the extension header buffer the current `ext_hdr`
468            // starts and ends so we can patch its next header value.
469            loop {
470                // This should never panic because if we panic, it means that we got a
471                // `None` value from `iter.next()` which would mean we exhausted all the
472                // extension headers while looking for the fragment header, meaning there
473                // is no fragment header. This function should never be called if there
474                // is no fragment extension header in the packet.
475                let next_ext_hdr = iter
476                    .next()
477                    .expect("exhausted all extension headers without finding fragment header");
478
479                if let Ipv6ExtensionHeader::Fragment { .. } = next_ext_hdr {
480                    // The next extension header is the fragment header
481                    // so we copy the buffer before and after the extension header
482                    // into `bytes` and patch the next header value within the
483                    // current extension header in `bytes`.
484
485                    // Header position relative to the extension header buffer.
486                    let fragment_hdr_start = ext_hdr_end - IPV6_FIXED_HDR_LEN;
487
488                    // Size of the fragment header should be exactly `IPV6_FRAGMENT_EXT_HDR_LEN`.
489                    let fragment_hdr_end = fragment_hdr_start + IPV6_FRAGMENT_EXT_HDR_LEN;
490                    assert_eq!(fragment_hdr_end, iter.context().position - IPV6_FIXED_HDR_LEN);
491
492                    let extension_hdr_bytes = self.extension_hdrs.bytes();
493
494                    // Copy extension headers that appear before the fragment header
495                    bytes.extend_from_slice(&extension_hdr_bytes[..fragment_hdr_start]);
496
497                    // Copy extension headers that appear after the fragment header
498                    bytes.extend_from_slice(&extension_hdr_bytes[fragment_hdr_end..]);
499
500                    // Update the current `ext_hdr`'s next header value to the next
501                    // header value within the fragment extension header.
502                    match ext_hdr {
503                        // The next header value is located in the first byte of the
504                        // extension header.
505                        Ipv6ExtensionHeader::HopByHopOptions { .. }
506                        | Ipv6ExtensionHeader::DestinationOptions { .. }
507                        | Ipv6ExtensionHeader::Routing { .. } => {
508                            bytes[ext_hdr_start] = iter.context().next_header;
509                        }
510                        Ipv6ExtensionHeader::Fragment { .. } => unreachable!(
511                            "If we had a fragment header before `ext_hdr`, we should have used that instead"
512                        ),
513                    }
514
515                    break;
516                }
517
518                ext_hdr = next_ext_hdr;
519                ext_hdr_start = ext_hdr_end;
520                ext_hdr_end = iter.context().position;
521            }
522        }
523
524        // `bytes`'s length should be exactly `expected_bytes_len`.
525        assert_eq!(bytes.len(), expected_bytes_len);
526        bytes
527    }
528
529    fn header_len(&self) -> usize {
530        Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.bytes().len()
531    }
532
533    fn fragment_header_present(&self) -> bool {
534        for ext_hdr in self.extension_hdrs.iter() {
535            if matches!(ext_hdr, Ipv6ExtensionHeader::Fragment { .. }) {
536                return true;
537            }
538        }
539        false
540    }
541
542    /// Construct a builder with the same contents as this packet.
543    pub fn builder(&self) -> Ipv6PacketBuilder {
544        Ipv6PacketBuilder {
545            dscp_and_ecn: self.dscp_and_ecn(),
546            flowlabel: self.flowlabel(),
547            hop_limit: self.hop_limit(),
548            proto: self.proto(),
549            src_ip: self.src_ip(),
550            dst_ip: self.dst_ip(),
551        }
552    }
553
554    /// Performs the header translation part of NAT64 as described in [RFC
555    /// 7915].
556    ///
557    /// `nat64_translate` follows the rules described in RFC 7915 to construct
558    /// the IPv4 equivalent of this IPv6 packet. If the payload is a TCP segment
559    /// or a UDP packet, its checksum will be updated. If the payload is an
560    /// ICMPv6 packet, it will be converted to the equivalent ICMPv4 packet. For
561    /// all other payloads, the payload will be unchanged, and the IP header will
562    /// be translated. On success, a [`Serializer`] is returned which describes
563    /// the new packet to be sent.
564    ///
565    /// Note that the IPv4 TTL/IPv6 Hop Limit field is not modified. It is the
566    /// caller's responsibility to decrement and process this field per RFC
567    /// 7915.
568    ///
569    /// In some cases, the packet has no IPv4 equivalent, in which case the
570    /// value [`Nat64TranslationResult::Drop`] will be returned, instructing the
571    /// caller to silently drop the packet.
572    ///
573    /// # Errors
574    ///
575    /// `nat64_translate` will return an error if support has not yet been
576    /// implemented for translating a particular IP protocol.
577    ///
578    /// [RFC 7915]: https://datatracker.ietf.org/doc/html/rfc7915
579    pub fn nat64_translate(
580        &self,
581        v4_src_addr: Ipv4Addr,
582        v4_dst_addr: Ipv4Addr,
583    ) -> Nat64TranslationResult<
584        impl Serializer<NoOpSerializationContext, Buffer = EmptyBuf> + Debug + '_,
585        Nat64Error,
586    > {
587        // A single `Serializer` type so that all possible return values from
588        // this function have the same type.
589        #[derive(Debug)]
590        enum Nat64Serializer<T, U, O> {
591            Tcp(T),
592            Udp(U),
593            Other(O),
594        }
595        impl<T, U, O> Serializer<NoOpSerializationContext> for Nat64Serializer<T, U, O>
596        where
597            T: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
598            U: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
599            O: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
600        {
601            type Buffer = EmptyBuf;
602            fn serialize<B, P>(
603                self,
604                context: &mut NoOpSerializationContext,
605                outer: PacketConstraints,
606                provider: P,
607            ) -> Result<B, (SerializeError<P::Error>, Self)>
608            where
609                B: GrowBufferMut,
610                P: BufferProvider<Self::Buffer, B>,
611            {
612                match self {
613                    Nat64Serializer::Tcp(serializer) => serializer
614                        .serialize(context, outer, provider)
615                        .map_err(|(err, ser)| (err, Nat64Serializer::Tcp(ser))),
616                    Nat64Serializer::Udp(serializer) => serializer
617                        .serialize(context, outer, provider)
618                        .map_err(|(err, ser)| (err, Nat64Serializer::Udp(ser))),
619                    Nat64Serializer::Other(serializer) => serializer
620                        .serialize(context, outer, provider)
621                        .map_err(|(err, ser)| (err, Nat64Serializer::Other(ser))),
622                }
623            }
624
625            fn serialize_new_buf<B: GrowBufferMut, A: LayoutBufferAlloc<B>>(
626                &self,
627                context: &mut NoOpSerializationContext,
628                outer: PacketConstraints,
629                alloc: A,
630            ) -> Result<B, SerializeError<A::Error>> {
631                match self {
632                    Nat64Serializer::Tcp(serializer) => {
633                        serializer.serialize_new_buf(context, outer, alloc)
634                    }
635                    Nat64Serializer::Udp(serializer) => {
636                        serializer.serialize_new_buf(context, outer, alloc)
637                    }
638                    Nat64Serializer::Other(serializer) => {
639                        serializer.serialize_new_buf(context, outer, alloc)
640                    }
641                }
642            }
643        }
644
645        impl<T, U, O> NestableSerializer for Nat64Serializer<T, U, O>
646        where
647            T: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
648            U: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
649            O: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
650        {
651        }
652
653        // TODO(https://fxbug.dev/42174049): Add support for fragmented packets
654        // forwarding.
655        if self.fragment_header_present() {
656            return Nat64TranslationResult::Err(Nat64Error::NotImplemented);
657        }
658
659        let v4_builder = |v4_proto| {
660            let mut builder =
661                Ipv4PacketBuilder::new(v4_src_addr, v4_dst_addr, self.hop_limit(), v4_proto);
662            builder.dscp_and_ecn(self.dscp_and_ecn());
663
664            // The IPv4 header length is 20 bytes (so IHL field value is 5), as
665            // no header options are present in translated IPv4 packet.
666            // As per RFC 7915 Section 5.1:
667            //  "Internet Header Length:  5 (no IPv4 options)"
668            const IPV4_HEADER_LEN_BYTES: usize = HDR_PREFIX_LEN;
669
670            // As per RFC 7915 Section 5.1,
671            //    "Flags:  The More Fragments flag is set to zero.  The Don't Fragment
672            //        (DF) flag is set as follows: If the size of the translated IPv4
673            //        packet is less than or equal to 1260 bytes, it is set to zero;
674            //        otherwise, it is set to one."
675            builder.df_flag(self.body().len() + IPV4_HEADER_LEN_BYTES > 1260);
676
677            // TODO(https://fxbug.dev/42174049): This needs an update once
678            // we don't return early for fragment_header_present case.
679            builder.fragment_offset(FragmentOffset::ZERO);
680            builder.mf_flag(false);
681
682            builder
683        };
684
685        match self.proto() {
686            Ipv6Proto::Proto(IpProto::Tcp) => {
687                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Tcp));
688                let args = TcpParseArgs::new(self.src_ip(), self.dst_ip());
689                // TODO(https://fxbug.dev/42174405): We're doing roughly similar work
690                // in valid/invalid parsing case. Remove match statement and
691                // update the checksum in place without needing to parse the TCP
692                // segment once we have ability to update the checksum.
693                match TcpSegment::parse(&mut self.body.as_bytes(), args) {
694                    Ok(tcp) => {
695                        // Creating a new tcp_serializer for IPv6 packet from
696                        // the existing one ensures that checksum is
697                        // updated due to changed IP addresses.
698                        let tcp_serializer =
699                            Nat64Serializer::Tcp(tcp.into_serializer(v4_src_addr, v4_dst_addr));
700                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(tcp_serializer))
701                    }
702                    Err(msg) => {
703                        debug!("Parsing of TCP segment failed: {:?}", msg);
704
705                        // This means we can't create a TCP segment builder with
706                        // updated checksum. Parsing may fail due to a variety of
707                        // reasons, including incorrect checksum in incoming packet.
708                        // We should still return a packet with IP payload copied
709                        // as is from IPv6 to IPv4. This handling is similar to
710                        // the handling of the case with unsupported protocol type
711                        // as done in `Ipv6Proto::Other(val)` case below. The similar
712                        // reasoning from RFC appiles here as well.
713                        let common_serializer =
714                            Nat64Serializer::Other(self.body().into_serializer());
715                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
716                    }
717                }
718            }
719
720            // TODO(https://fxbug.dev/42174405): We're doing roughly similar work
721            // in valid/invalid parsing case. Remove match statement and
722            // update the checksum in place without needing to parse the UDP segment
723            // once we have ability to update checksum.
724            Ipv6Proto::Proto(IpProto::Udp) => {
725                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Udp));
726                let args = UdpParseArgs::new(self.src_ip(), self.dst_ip());
727                match UdpPacket::parse(&mut self.body.as_bytes(), args) {
728                    Ok(udp) => {
729                        // Creating a new udp_serializer for IPv6 packet from
730                        // the existing one ensures that checksum is
731                        // updated due to changed IP addresses.
732                        let udp_serializer =
733                            Nat64Serializer::Udp(udp.into_serializer(v4_src_addr, v4_dst_addr));
734                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(udp_serializer))
735                    }
736                    Err(msg) => {
737                        debug!("Parsing of UDP packet failed: {:?}", msg);
738
739                        // This means we can't create a UDP packet builder with
740                        // updated checksum. Parsing may fail due to a variety of
741                        // reasons, including incorrect checksum in incoming packet.
742                        // We should still return a packet with IP payload copied
743                        // as is from IPv6 to IPv4. This handling is similar to
744                        // the handling of the case with unsupported protocol type
745                        // as done in `Ipv6Proto::Other(val)` case below. The similar
746                        // reasoning from RFC appiles here as well.
747
748                        let common_serializer =
749                            Nat64Serializer::Other(self.body().into_serializer());
750                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
751                    }
752                }
753            }
754
755            // TODO(https://fxbug.dev/42174051): Implement ICMP packet translation
756            // support here.
757            Ipv6Proto::Icmpv6 => Nat64TranslationResult::Err(Nat64Error::NotImplemented),
758
759            // For all other protocols, an IPv4 packet must be forwarded even if
760            // the transport layer checksum update is not implemented.
761            // As per RFC 7915 Section 5.1,
762            //     "Protocol:
763            //       ...
764            //
765            //       For the first 'next header' that does not match one of the cases
766            //       above, its Next Header value (which contains the transport
767            //       protocol number) is copied to the protocol field in the IPv4
768            //       header.  This means that all transport protocols are translated.
769            //
770            //       Note:  Some translated protocols will fail at the receiver for
771            //          various reasons: some are known to fail when translated (e.g.,
772            //          IPsec Authentication Header (51)), and others will fail
773            //          checksum validation if the address translation is not checksum
774            //          neutral [RFC6052] and the translator does not update the
775            //          transport protocol's checksum (because the translator doesn't
776            //          support recalculating the checksum for that transport protocol;
777            //          see Section 5.5)."
778            Ipv6Proto::Other(val) => {
779                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(val));
780                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
781                Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
782            }
783
784            Ipv6Proto::NoNextHeader => {
785                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(Ipv6Proto::NoNextHeader.into()));
786                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
787                Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
788            }
789
790            // Don't forward packets that use IANA's reserved protocol; they're
791            // invalid.
792            Ipv6Proto::Proto(IpProto::Reserved) => Nat64TranslationResult::Drop,
793        }
794    }
795
796    /// Copies the packet (Header + Extensions + Body) into a `Vec`.
797    pub fn to_vec(&self) -> Vec<u8> {
798        let Ipv6Packet { fixed_hdr, extension_hdrs, body, proto: _ } = self;
799        let mut buf = Vec::with_capacity(
800            Ref::bytes(&fixed_hdr).len() + extension_hdrs.bytes().len() + body.as_bytes().len(),
801        );
802        buf.extend(Ref::bytes(&fixed_hdr));
803        buf.extend(extension_hdrs.bytes());
804        buf.extend(body.as_bytes());
805        buf
806    }
807}
808
809impl<B: SplitByteSliceMut> Ipv6Packet<B> {
810    /// Set the source IP address.
811    pub fn set_src_ip(&mut self, addr: Ipv6Addr) {
812        self.fixed_hdr.src_ip = addr;
813    }
814
815    /// Set the destination IP address.
816    pub fn set_dst_ip(&mut self, addr: Ipv6Addr) {
817        self.fixed_hdr.dst_ip = addr;
818    }
819
820    /// Set the hop limit.
821    pub fn set_hop_limit(&mut self, hlim: u8) {
822        self.fixed_hdr.hop_limit = hlim;
823    }
824
825    /// The packet body.
826    pub fn body_mut(&mut self) -> &mut [u8] {
827        &mut self.body
828    }
829
830    /// Provides simultaneous access to header, extension headers, and mutable
831    /// body.
832    pub fn parts_with_body_mut(&mut self) -> (&FixedHeader, ExtensionHeaders<'_>, &mut [u8]) {
833        (&self.fixed_hdr, ExtensionHeaders(self.extension_hdrs.as_ref()), &mut self.body)
834    }
835}
836
837impl<B: SplitByteSlice> Debug for Ipv6Packet<B> {
838    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
839        f.debug_struct("Ipv6Packet")
840            .field("src_ip", &self.src_ip())
841            .field("dst_ip", &self.dst_ip())
842            .field("hop_limit", &self.hop_limit())
843            .field("proto", &self.proto())
844            .field("dscp", &self.dscp_and_ecn().dscp())
845            .field("ecn", &self.dscp_and_ecn().ecn())
846            .field("flowlabel", &self.flowlabel())
847            .field("extension headers", &"TODO")
848            .field("body", &alloc::format!("<{} bytes>", self.body.len()))
849            .finish()
850    }
851}
852
853/// The extension headers in an [`Ipv6Packet`].
854pub struct ExtensionHeaders<'a>(Records<&'a [u8], Ipv6ExtensionHeaderImpl>);
855
856impl<'a> ExtensionHeaders<'a> {
857    /// Returns an iterator over the extension headers.
858    pub fn iter(&self) -> impl Iterator<Item = Ipv6ExtensionHeader<'_>> {
859        self.0.iter()
860    }
861
862    /// Returns the raw bytes of the extension headers.
863    pub fn bytes(&self) -> &[u8] {
864        self.0.bytes()
865    }
866}
867
868/// We were unable to parse the extension headers.
869///
870/// As a result, we were unable to determine the upper-layer Protocol Number
871/// (which is stored in the last extension header's Next Header field) and were
872/// unable figure out where the body begins.
873#[derive(Copy, Clone, Debug, Eq, PartialEq)]
874pub struct ExtHdrParseError;
875
876/// A partially parsed and not yet validated IPv6 packet.
877///
878/// `Ipv6PacketRaw` provides minimal parsing of an IPv6 packet, namely
879/// it only requires that the fixed header part ([`HeaderPrefix`]) be retrieved,
880/// all the other parts of the packet may be missing when attempting to create
881/// it.
882///
883/// [`Ipv6Packet`] provides a [`FromRaw`] implementation that can be used to
884/// validate an `Ipv6PacketRaw`.
885pub struct Ipv6PacketRaw<B> {
886    /// A raw packet always contains at least a fully parsed `FixedHeader`.
887    fixed_hdr: Ref<B, FixedHeader>,
888    /// When `extension_hdrs` is [`MaybeParsed::Complete`], it contains the
889    /// `RecordsRaw` that can be validated for full extension headers parsing.
890    /// Otherwise, it just contains the extension header bytes that were
891    /// successfully consumed before reaching an error (typically "buffer
892    /// exhausted").
893    extension_hdrs: MaybeParsed<RecordsRaw<B, Ipv6ExtensionHeaderImpl>, B>,
894    /// The body and upper-layer Protocol Number.
895    ///
896    /// If extension headers failed to parse, this will be
897    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
898    /// find the bounds of the upper-layer payload and to find that last
899    /// extension header's Next Header field, which is the Protocol Number of
900    /// the upper-layer payload.
901    ///
902    /// The body will be [`MaybeParsed::Complete`] if all the body bytes were
903    /// consumed (as stated by the header's payload length value) or
904    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
905    /// otherwise.
906    body_proto: Result<(MaybeParsed<B, B>, Ipv6Proto), ExtHdrParseError>,
907}
908
909impl<B> Ipv6PacketRaw<B> {
910    /// Returns a mutable reference to the body bytes of this [`Ipv6PacketRaw`].
911    ///
912    /// Might not be complete if a full packet was not received.
913    pub fn body_mut(&mut self) -> Option<&mut B> {
914        match self.body_proto {
915            Ok(ref mut b) => match b {
916                (MaybeParsed::Complete(b), _) => Some(b),
917                (MaybeParsed::Incomplete(b), _) => Some(b),
918            },
919            Err(_) => None,
920        }
921    }
922}
923
924impl<B: SplitByteSlice> Ipv6Header for Ipv6PacketRaw<B> {
925    fn get_fixed_header(&self) -> &FixedHeader {
926        &self.fixed_hdr
927    }
928}
929
930impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv6PacketRaw<B> {
931    type Error = Ipv6ParseError;
932
933    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
934        let fixed_hdr = buffer
935            .take_obj_front::<FixedHeader>()
936            .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
937        let payload_len = fixed_hdr.payload_len.get().into();
938        // Trim the buffer if it exceeds the length specified in the header.
939        let _: Option<B> = buffer.len().checked_sub(payload_len).map(|padding| {
940            buffer.take_back(padding).unwrap_or_else(|| {
941                panic!("buffer.len()={} padding={}", buffer.len(), padding);
942            })
943        });
944
945        let mut extension_hdr_context = Ipv6ExtensionHeaderParsingContext::new(fixed_hdr.next_hdr);
946
947        let extension_hdrs =
948            RecordsRaw::parse_raw_with_mut_context(&mut buffer, &mut extension_hdr_context)
949                .map_incomplete(|(b, _)| b);
950
951        let body_proto = match &extension_hdrs {
952            MaybeParsed::Complete(r) => {
953                let _: &RecordsRaw<B, _> = r;
954                // If we have extension headers our context's
955                // (`extension_hdr_context`) `next_header` would be updated with
956                // the last extension header's Next Header value. This will also
957                // work if we don't have any extension headers. Let's consider
958                // that scenario: When we have no extension headers, the Next
959                // Header value in the fixed header will be a valid upper layer
960                // protocol value.  `parse_bv_with_mut_context` will return
961                // almost immediately without doing any actual work when it
962                // checks the context's (`extension_hdr_context`) `next_header`
963                // value and ends parsing since, according to our context, its
964                // data is for an upper layer protocol. Now, since nothing was
965                // parsed, our context was never modified, so the next header
966                // value it was initialized with when calling
967                // `Ipv6ExtensionHeaderParsingContext::new`, will not have
968                // changed. We simply use that value and assign it to proto
969                // below.
970
971                // Extension header raw parsing only finishes when we have a
972                // valid next header that is meant for the upper layer. The
973                // assertion below enforces that contract.
974                assert!(is_valid_next_header_upper_layer(extension_hdr_context.next_header));
975                let proto = Ipv6Proto::from(extension_hdr_context.next_header);
976                let body = MaybeParsed::new_with_min_len(
977                    buffer.into_rest(),
978                    payload_len.saturating_sub(extension_hdrs.len()),
979                );
980                Ok((body, proto))
981            }
982            MaybeParsed::Incomplete(b) => {
983                let _: &B = b;
984                Err(ExtHdrParseError)
985            }
986        };
987
988        Ok(Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto })
989    }
990
991    fn parse_metadata(&self) -> ParseMetadata {
992        let header_len = Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.len();
993        let body_len = self.body_proto.as_ref().map(|(b, _p)| b.len()).unwrap_or(0);
994        ParseMetadata::from_packet(header_len, body_len, 0)
995    }
996}
997
998impl<B: SplitByteSlice> Ipv6PacketRaw<B> {
999    /// Returns the body and upper-layer Protocol Number.
1000    ///
1001    /// If extension headers failed to parse, `body_proto` returns
1002    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1003    /// find the bounds of the upper-layer payload and to find that last
1004    /// extension header's Next Header field, which is the Protocol Number of
1005    /// the upper-layer payload.
1006    ///
1007    /// The returned body will be [`MaybeParsed::Complete`] if all the body
1008    /// bytes were consumed (as stated by the header's payload length value) or
1009    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
1010    /// otherwise.
1011    pub fn body_proto(&self) -> Result<(MaybeParsed<&[u8], &[u8]>, Ipv6Proto), ExtHdrParseError> {
1012        self.body_proto
1013            .as_ref()
1014            .map(|(mp, proto)| {
1015                (mp.as_ref().map(|b| b.deref()).map_incomplete(|b| b.deref()), *proto)
1016            })
1017            .map_err(|e| *e)
1018    }
1019
1020    /// Returns the body.
1021    ///
1022    /// If extension headers failed to parse, `body` returns
1023    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1024    /// find the bounds of the upper-layer payload.
1025    ///
1026    /// The returned body will be [`MaybeParsed::Complete`] if all the body
1027    /// bytes were consumed (as stated by the header's payload length value) or
1028    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
1029    /// otherwise.
1030    pub fn body(&self) -> Result<MaybeParsed<&[u8], &[u8]>, ExtHdrParseError> {
1031        self.body_proto().map(|(body, _proto)| body)
1032    }
1033
1034    /// Returns the upper-layer Protocol Number.
1035    ///
1036    /// If extension headers failed to parse, `body_proto` returns
1037    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1038    /// find the last extension header's Next Header field, which is the
1039    /// Protocol Number of the upper-layer payload.
1040    pub fn proto(&self) -> Result<Ipv6Proto, ExtHdrParseError> {
1041        self.body_proto().map(|(_body, proto)| proto)
1042    }
1043}
1044
1045impl<B: SplitByteSliceMut> Ipv6PacketRaw<B> {
1046    /// Set the source IP address.
1047    pub fn set_src_ip(&mut self, addr: Ipv6Addr) {
1048        self.fixed_hdr.src_ip = addr;
1049    }
1050
1051    /// Set the destination IP address.
1052    pub fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1053        self.fixed_hdr.dst_ip = addr;
1054    }
1055}
1056
1057/// A next header that may be either a next layer header or an IPv6 extension
1058/// header.
1059pub enum NextHeader {
1060    /// A next layer header follows.
1061    NextLayer(Ipv6Proto),
1062    /// An extension header follows.
1063    Extension(Ipv6ExtHdrType),
1064}
1065
1066impl From<NextHeader> for u8 {
1067    fn from(next_hdr: NextHeader) -> Self {
1068        match next_hdr {
1069            NextHeader::NextLayer(n) => n.into(),
1070            NextHeader::Extension(e) => e.into(),
1071        }
1072    }
1073}
1074
1075mod sealed {
1076    use super::*;
1077    /// A marker trait for IPv6 headers that can be serialized before header
1078    /// `T`.
1079    ///
1080    /// This trait is used to enforce IPv6 extension header ordering according
1081    /// to [RFC 8200 Section 4.1].
1082    ///
1083    /// [RFC 8200 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.1
1084    pub trait Ipv6HeaderBefore<T> {}
1085
1086    impl<'a, O, T> Ipv6HeaderBefore<T> for &'a O where O: Ipv6HeaderBefore<T> {}
1087
1088    /// A trait abstracting all types of IPv6 header builders.
1089    pub trait Ipv6HeaderBuilder {
1090        /// Returns an immutable reference to the fixed header builder.
1091        fn fixed_header(&self) -> &Ipv6PacketBuilder;
1092
1093        /// Returns the total header length of the extension headers, including
1094        /// previous extension headers, but excluding the fixed header size.
1095        fn extension_headers_len(&self) -> usize;
1096
1097        /// Serializes the header into `buffer`.
1098        ///
1099        /// `next_header` is the header immediately after the current one.
1100        /// `payload_len` is the total size of the frame after this header.
1101        fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1102            &self,
1103            buffer: &mut BV,
1104            next_header: NextHeader,
1105            payload_len: usize,
1106        );
1107    }
1108}
1109use sealed::{Ipv6HeaderBefore, Ipv6HeaderBuilder};
1110
1111impl<'a, O> Ipv6HeaderBuilder for &'a O
1112where
1113    O: Ipv6HeaderBuilder,
1114{
1115    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1116        O::fixed_header(self)
1117    }
1118
1119    fn extension_headers_len(&self) -> usize {
1120        O::extension_headers_len(self)
1121    }
1122
1123    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1124        &self,
1125        buffer: &mut BV,
1126        next_header: NextHeader,
1127        payload_len: usize,
1128    ) {
1129        O::serialize_header(self, buffer, next_header, payload_len)
1130    }
1131}
1132
1133/// A helper macro to implement `PacketBuilder` methods for implementers of
1134/// `Ipv6HeaderBuilder`.
1135///
1136/// This can't be a blanket impl because `PacketBuilder` is a foreign trait.
1137macro_rules! impl_packet_builder_base {
1138    {} => {
1139        fn constraints(&self) -> PacketConstraints {
1140            let ext_headers = self.extension_headers_len();
1141            let header_len = IPV6_FIXED_HDR_LEN + ext_headers;
1142            let footer_len = 0;
1143            let min_body_len = 0;
1144            // Extension headers take from the IPv6 available payload size.
1145            // See RFC 8200 Section 3 for details.
1146            let max_body_len = IPV6_MAX_PAYLOAD_LENGTH - ext_headers;
1147            PacketConstraints::new(header_len, footer_len, min_body_len, max_body_len)
1148        }
1149    }
1150}
1151
1152macro_rules! impl_packet_builder {
1153    {} => {
1154        fn context_state(&self) -> C::ContextState {
1155            C::envelope_to_state(IpEnvelope::new(self.extension_headers_len() > 0))
1156        }
1157
1158        fn serialize(
1159            &self,
1160            _context: &mut C,
1161            target: &mut SerializeTarget<'_>,
1162            body: FragmentedBytesMut<'_, '_>,
1163        ) {
1164            let mut bv = &mut target.header;
1165            self.serialize_header(
1166                &mut bv,
1167                NextHeader::NextLayer(
1168                    <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::proto(self.fixed_header())
1169                ),
1170                body.len(),
1171            );
1172        }
1173    }
1174}
1175
1176macro_rules! impl_partial_packet_builder {
1177    {} => {
1178        fn partial_serialize(
1179            &self,
1180            _context: &mut C,
1181            body_len: usize,
1182            mut buffer: &mut [u8],
1183        ) {
1184            self.serialize_header(
1185                &mut &mut buffer,
1186                NextHeader::NextLayer(
1187                    <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::proto(self.fixed_header())
1188                ),
1189                body_len,
1190            );
1191        }
1192    }
1193}
1194/// A builder for IPv6 packets.
1195#[derive(Debug, Clone, Eq, PartialEq)]
1196pub struct Ipv6PacketBuilder {
1197    dscp_and_ecn: DscpAndEcn,
1198    flowlabel: u32,
1199    hop_limit: u8,
1200    // The protocol number of the upper layer protocol, not the Next Header
1201    // value of the first extension header (if one exists).
1202    proto: Ipv6Proto,
1203    src_ip: Ipv6Addr,
1204    dst_ip: Ipv6Addr,
1205}
1206
1207impl Ipv6PacketBuilder {
1208    /// Constructs a new `Ipv6PacketBuilder`.
1209    ///
1210    /// The `proto` field encodes the protocol number identifying the upper
1211    /// layer payload, not the Next Header value of the first extension header
1212    /// (if one exists).
1213    pub fn new<S: Into<Ipv6Addr>, D: Into<Ipv6Addr>>(
1214        src_ip: S,
1215        dst_ip: D,
1216        hop_limit: u8,
1217        proto: Ipv6Proto,
1218    ) -> Ipv6PacketBuilder {
1219        Ipv6PacketBuilder {
1220            dscp_and_ecn: DscpAndEcn::default(),
1221            flowlabel: 0,
1222            hop_limit,
1223            proto,
1224            src_ip: src_ip.into(),
1225            dst_ip: dst_ip.into(),
1226        }
1227    }
1228
1229    /// Set the Differentiated Services Code Point (DSCP) and the Explicit
1230    /// Congestion Notification (ECN).
1231    pub fn dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1232        self.dscp_and_ecn = dscp_and_ecn;
1233    }
1234
1235    /// Set the flowlabel.
1236    ///
1237    /// # Panics
1238    ///
1239    /// `flowlabel` panics if `flowlabel` is greater than 2^20 - 1.
1240    pub fn flowlabel(&mut self, flowlabel: u32) {
1241        assert!(flowlabel <= 1 << 20, "invalid flowlabel: {:x}", flowlabel);
1242        self.flowlabel = flowlabel;
1243    }
1244}
1245
1246impl Ipv6HeaderBuilder for Ipv6PacketBuilder {
1247    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1248        self
1249    }
1250
1251    fn extension_headers_len(&self) -> usize {
1252        0
1253    }
1254
1255    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1256        &self,
1257        buffer: &mut BV,
1258        next_header: NextHeader,
1259        payload_len: usize,
1260    ) {
1261        buffer
1262            .write_obj_front(&FixedHeader::new(
1263                self.dscp_and_ecn,
1264                self.flowlabel,
1265                {
1266                    // The caller promises to supply a body whose length
1267                    // does not exceed max_body_len. Doing this as a
1268                    // debug_assert (rather than an assert) is fine because,
1269                    // with debug assertions disabled, we'll just write an
1270                    // incorrect header value, which is acceptable if the
1271                    // caller has violated their contract.
1272                    debug_assert!(payload_len <= core::u16::MAX as usize);
1273                    payload_len as u16
1274                },
1275                next_header.into(),
1276                self.hop_limit,
1277                self.src_ip,
1278                self.dst_ip,
1279            ))
1280            .expect("not enough bytes for IPv6 fixed header");
1281    }
1282}
1283
1284impl NestablePacketBuilder for Ipv6PacketBuilder {
1285    impl_packet_builder_base! {}
1286}
1287
1288impl<C: IpSerializationContext<Ipv6>> PacketBuilder<C> for Ipv6PacketBuilder {
1289    impl_packet_builder! {}
1290}
1291
1292impl<C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C> for Ipv6PacketBuilder {
1293    impl_partial_packet_builder! {}
1294}
1295
1296/// A builder for Ipv6 packets with HBH Options.
1297#[derive(Debug, Clone)]
1298pub struct Ipv6PacketBuilderWithHbhOptions<'a, I> {
1299    prefix_builder: Ipv6PacketBuilder,
1300    hbh_options: AlignedRecordSequenceBuilder<HopByHopOption<'a>, I>,
1301}
1302
1303impl<'a, I> Ipv6PacketBuilderWithHbhOptions<'a, I>
1304where
1305    I: Iterator + Clone,
1306    I::Item: Borrow<HopByHopOption<'a>>,
1307{
1308    /// Creates a IPv6 packet builder with a Hop By Hop Options extension header.
1309    pub fn new<T: IntoIterator<Item = I::Item, IntoIter = I>>(
1310        prefix_builder: Ipv6PacketBuilder,
1311        options: T,
1312    ) -> Option<Ipv6PacketBuilderWithHbhOptions<'a, I>> {
1313        let iter = options.into_iter();
1314        // https://tools.ietf.org/html/rfc2711#section-2.1 specifies that
1315        // an RouterAlert option can only appear once.
1316        if iter
1317            .clone()
1318            .filter(|r| matches!(r.borrow().data, HopByHopOptionData::RouterAlert { .. }))
1319            .count()
1320            > 1
1321        {
1322            return None;
1323        }
1324        let hbh_options = AlignedRecordSequenceBuilder::new(2, iter);
1325        // And we don't want our options to become too long.
1326        if next_multiple_of_eight(2 + hbh_options.serialized_len()) > IPV6_HBH_OPTIONS_MAX_LEN {
1327            return None;
1328        }
1329        Some(Ipv6PacketBuilderWithHbhOptions { prefix_builder, hbh_options })
1330    }
1331
1332    fn aligned_hbh_len(&self) -> usize {
1333        let opt_len = self.hbh_options.serialized_len();
1334        let hbh_len = opt_len + 2;
1335        next_multiple_of_eight(hbh_len)
1336    }
1337}
1338
1339fn next_multiple_of_eight(x: usize) -> usize {
1340    (x + 7) & (!7)
1341}
1342
1343impl<C: IpSerializationContext<Ipv6>> IpPacketBuilder<C, Ipv6> for Ipv6PacketBuilder {
1344    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1345        Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto)
1346    }
1347
1348    fn src_ip(&self) -> Ipv6Addr {
1349        self.src_ip
1350    }
1351
1352    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1353        self.src_ip = addr;
1354    }
1355
1356    fn dst_ip(&self) -> Ipv6Addr {
1357        self.dst_ip
1358    }
1359
1360    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1361        self.dst_ip = addr;
1362    }
1363
1364    fn proto(&self) -> Ipv6Proto {
1365        self.proto
1366    }
1367
1368    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1369        self.dscp_and_ecn = dscp_and_ecn;
1370    }
1371}
1372
1373impl<'a, I> Ipv6HeaderBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1374where
1375    I: Iterator + Clone,
1376    I::Item: Borrow<HopByHopOption<'a>>,
1377{
1378    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1379        &self.prefix_builder
1380    }
1381
1382    fn extension_headers_len(&self) -> usize {
1383        self.prefix_builder.extension_headers_len() + self.aligned_hbh_len()
1384    }
1385
1386    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1387        &self,
1388        buffer: &mut BV,
1389        next_header: NextHeader,
1390        payload_len: usize,
1391    ) {
1392        let aligned_hbh_len = self.aligned_hbh_len();
1393        // The next header in the fixed header now should be 0 (Hop-by-Hop Extension Header)
1394        self.prefix_builder.serialize_header(
1395            buffer,
1396            NextHeader::Extension(Ipv6ExtHdrType::HopByHopOptions),
1397            payload_len + aligned_hbh_len,
1398        );
1399        // take the first two bytes to write in proto and length information.
1400        let mut hbh_header = buffer.take_front(aligned_hbh_len).unwrap();
1401        let hbh_header = hbh_header.as_mut();
1402        hbh_header[0] = next_header.into();
1403        hbh_header[1] = u8::try_from((aligned_hbh_len - 8) / 8).expect("extension header too big");
1404        self.hbh_options.serialize_into(&mut hbh_header[2..]);
1405    }
1406}
1407
1408impl<'a, I> NestablePacketBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1409where
1410    I: Iterator + Clone,
1411    I::Item: Borrow<HopByHopOption<'a>>,
1412{
1413    impl_packet_builder_base! {}
1414}
1415
1416impl<'a, I, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1417    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1418where
1419    I: Iterator + Clone,
1420    I::Item: Borrow<HopByHopOption<'a>>,
1421{
1422    impl_packet_builder! {}
1423}
1424
1425impl<'a, I, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1426    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1427where
1428    I: Iterator + Clone,
1429    I::Item: Borrow<HopByHopOption<'a>>,
1430{
1431    impl_partial_packet_builder! {}
1432}
1433
1434impl<'a, C: IpSerializationContext<Ipv6>, I> IpPacketBuilder<C, Ipv6>
1435    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1436where
1437    I: Iterator<Item: Borrow<HopByHopOption<'a>>> + Debug + Default + Clone,
1438{
1439    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1440        Ipv6PacketBuilderWithHbhOptions::new(
1441            Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto),
1442            I::default(),
1443        )
1444        .expect("packet builder with no options should be valid")
1445    }
1446
1447    fn src_ip(&self) -> Ipv6Addr {
1448        self.prefix_builder.src_ip
1449    }
1450
1451    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1452        self.prefix_builder.src_ip = addr;
1453    }
1454
1455    fn dst_ip(&self) -> Ipv6Addr {
1456        self.prefix_builder.dst_ip
1457    }
1458
1459    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1460        self.prefix_builder.dst_ip = addr;
1461    }
1462
1463    fn proto(&self) -> Ipv6Proto {
1464        self.prefix_builder.proto
1465    }
1466
1467    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1468        <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::set_dscp_and_ecn(
1469            &mut self.prefix_builder,
1470            dscp_and_ecn,
1471        )
1472    }
1473}
1474
1475/// An IPv6 packet builder that includes the fragmentation header.
1476///
1477/// `Ipv6PacketBuilderWithFragmentHeader` wraps another compatible packet
1478/// builder to attach the fragment header on it.
1479///
1480/// See [RFC 8200 Section 2.5] for the fragment header format.
1481///
1482/// [RFC 8200 Section 2.5]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
1483#[derive(Debug, Eq, PartialEq)]
1484pub struct Ipv6PacketBuilderWithFragmentHeader<B> {
1485    header_builder: B,
1486    fragment_offset: FragmentOffset,
1487    more_fragments: bool,
1488    identification: u32,
1489}
1490
1491impl<B: Ipv6HeaderBefore<Self>> Ipv6PacketBuilderWithFragmentHeader<B> {
1492    /// Creates a new `Ipv6PacketBuilderWithFragmentHeader`.
1493    pub fn new(
1494        header_builder: B,
1495        fragment_offset: FragmentOffset,
1496        more_fragments: bool,
1497        identification: u32,
1498    ) -> Self {
1499        Self { header_builder, fragment_offset, more_fragments, identification }
1500    }
1501}
1502
1503impl<B> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> for Ipv6PacketBuilder {}
1504impl<B, I> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>>
1505    for Ipv6PacketBuilderWithHbhOptions<'_, I>
1506{
1507}
1508
1509/// A marker trait for all header builder types that can be used to construct
1510/// and serialize IPv6 headers using [`Ipv6PacketBuilderWithFragmentHeader`].
1511pub trait Ipv6PacketBuilderBeforeFragment:
1512    Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1513{
1514}
1515impl<B> Ipv6PacketBuilderBeforeFragment for B where
1516    B: Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1517{
1518}
1519
1520impl<B: Ipv6HeaderBuilder> Ipv6HeaderBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1521    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1522        self.header_builder.fixed_header()
1523    }
1524
1525    fn extension_headers_len(&self) -> usize {
1526        self.header_builder.extension_headers_len() + IPV6_FRAGMENT_EXT_HDR_LEN
1527    }
1528
1529    fn serialize_header<BB: SplitByteSliceMut, BV: BufferViewMut<BB>>(
1530        &self,
1531        buffer: &mut BV,
1532        next_header: NextHeader,
1533        payload_len: usize,
1534    ) {
1535        let Self { header_builder, fragment_offset, more_fragments, identification } = self;
1536        let payload_len = payload_len + IPV6_FRAGMENT_EXT_HDR_LEN;
1537        header_builder.serialize_header(
1538            buffer,
1539            NextHeader::Extension(Ipv6ExtHdrType::Fragment),
1540            payload_len,
1541        );
1542        buffer.write_obj_front(&u8::from(next_header)).unwrap();
1543        // Reserved.
1544        let _: BB = buffer.take_front_zero(1).unwrap();
1545        let more_fragments = u16::from(*more_fragments);
1546        buffer
1547            .write_obj_front(&U16::new(fragment_offset.into_raw() << 3 | more_fragments))
1548            .unwrap();
1549        buffer.write_obj_front(&U32::new(*identification)).unwrap();
1550    }
1551}
1552
1553impl<B: Ipv6HeaderBuilder> NestablePacketBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1554    impl_packet_builder_base! {}
1555}
1556
1557impl<B: Ipv6HeaderBuilder, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1558    for Ipv6PacketBuilderWithFragmentHeader<B>
1559{
1560    impl_packet_builder! {}
1561}
1562
1563impl<B: Ipv6HeaderBuilder, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1564    for Ipv6PacketBuilderWithFragmentHeader<B>
1565{
1566    impl_partial_packet_builder! {}
1567}
1568
1569/// Reassembles a fragmented packet into a parsed IP packet.
1570///
1571/// # Panics
1572///
1573/// Panics if the provided header is too small to hold a valid header.
1574pub(crate) fn reassemble_fragmented_packet<
1575    B: SplitByteSliceMut,
1576    BV: BufferViewMut<B>,
1577    I: Iterator<Item = Vec<u8>>,
1578>(
1579    mut buffer: BV,
1580    header: Vec<u8>,
1581    body_fragments: I,
1582) -> IpParseResult<Ipv6, ()> {
1583    assert!(header.len() >= IPV6_FIXED_HDR_LEN);
1584
1585    let bytes = buffer.as_mut();
1586
1587    // First, copy over the header data.
1588    bytes[0..header.len()].copy_from_slice(&header[..]);
1589    let mut byte_count = header.len();
1590
1591    // Next, copy over the body fragments.
1592    for p in body_fragments {
1593        bytes[byte_count..byte_count + p.len()].copy_from_slice(&p[..]);
1594        byte_count += p.len();
1595    }
1596
1597    //
1598    // Fix up the IPv6 header
1599    //
1600
1601    // For IPv6, the payload length is the sum of the length of the
1602    // extension headers and the packet body. The header as it is stored
1603    // includes the IPv6 fixed header and all extension headers, so
1604    // `bytes_count` is the sum of the size of the fixed header,
1605    // extension headers and packet body. To calculate the payload
1606    // length we subtract the size of the fixed header from the total
1607    // byte count of a reassembled packet.
1608    let payload_length = byte_count - IPV6_FIXED_HDR_LEN;
1609
1610    // Make sure that the payload length is not more than the maximum
1611    // possible IPv6 packet length.
1612    if payload_length > usize::from(core::u16::MAX) {
1613        return debug_err!(
1614            Err(ParseError::Format.into()),
1615            "fragmented packet payload length of {} bytes is too large",
1616            payload_length
1617        );
1618    }
1619
1620    // We know the call to `unwrap` will not fail because we verified the length
1621    // of `header` and copied it's bytes into `bytes`.
1622    let mut header = Ref::<_, FixedHeader>::from_prefix(bytes).unwrap().0;
1623
1624    // Update the payload length field.
1625    header.payload_len.set(u16::try_from(payload_length).unwrap());
1626
1627    Ok(())
1628}
1629
1630#[cfg(test)]
1631mod tests {
1632    use assert_matches::assert_matches;
1633    use packet::{Buf, FragmentedBuffer, ParseBuffer, PartialSerializeResult};
1634    use test_case::test_case;
1635
1636    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
1637    use crate::testutil::*;
1638
1639    use super::ext_hdrs::*;
1640    use super::*;
1641
1642    const DEFAULT_SRC_IP: Ipv6Addr =
1643        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1644    const DEFAULT_DST_IP: Ipv6Addr =
1645        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
1646
1647    const DEFAULT_V4_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1648    const DEFAULT_V4_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
1649
1650    #[test]
1651    fn test_parse_serialize_full_tcp() {
1652        use crate::testdata::syn_v6::*;
1653
1654        let mut buf = ETHERNET_FRAME.bytes;
1655        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1656        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1657
1658        let mut body = frame.body();
1659        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1660        verify_ipv6_packet(&packet, IPV6_PACKET);
1661
1662        // Verify serialization via builders.
1663        let buffer = packet
1664            .body()
1665            .into_serializer()
1666            .wrap_in(packet.builder())
1667            .wrap_in(frame.builder())
1668            .serialize_vec_outer(&mut NoOpSerializationContext)
1669            .unwrap();
1670        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1671
1672        // Verify serialization via `to_vec`.
1673        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1674    }
1675
1676    #[test]
1677    fn test_parse_serialize_full_udp() {
1678        use crate::testdata::dns_request_v6::*;
1679
1680        let mut buf = ETHERNET_FRAME.bytes;
1681        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1682        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1683
1684        let mut body = frame.body();
1685        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1686        verify_ipv6_packet(&packet, IPV6_PACKET);
1687
1688        // Verify serialization via builders.
1689        let buffer = packet
1690            .body()
1691            .into_serializer()
1692            .wrap_in(packet.builder())
1693            .wrap_in(frame.builder())
1694            .serialize_vec_outer(&mut NoOpSerializationContext)
1695            .unwrap();
1696        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1697
1698        // Verify serialization via `to_vec`.
1699        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1700    }
1701
1702    #[test]
1703    fn test_parse_serialize_with_extension_headers() {
1704        // NB; Use MLD as test data arbitrarily, because it includes IPv6
1705        // extension headers.
1706        use crate::testdata::mld_router_report::*;
1707
1708        let mut buf = REPORT;
1709        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1710        assert_eq!(packet.iter_extension_hdrs().count(), 1);
1711
1712        // NB: Don't verify serialization via builders, as they omit IPv6
1713        // extension headers.
1714
1715        // Verify serialization via `to_vec`.
1716        assert_eq!(&packet.to_vec()[..], REPORT);
1717    }
1718
1719    fn fixed_hdr_to_bytes(fixed_hdr: FixedHeader) -> [u8; IPV6_FIXED_HDR_LEN] {
1720        zerocopy::transmute!(fixed_hdr)
1721    }
1722
1723    // Return a new FixedHeader with reasonable defaults.
1724    fn new_fixed_hdr() -> FixedHeader {
1725        FixedHeader::new(
1726            DscpAndEcn::new(0, 2),
1727            0x77,
1728            0,
1729            IpProto::Tcp.into(),
1730            64,
1731            DEFAULT_SRC_IP,
1732            DEFAULT_DST_IP,
1733        )
1734    }
1735
1736    #[test]
1737    fn test_parse() {
1738        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
1739        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1740        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1741        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1742        assert_eq!(packet.flowlabel(), 0x77);
1743        assert_eq!(packet.hop_limit(), 64);
1744        assert_eq!(packet.fixed_hdr.next_hdr, IpProto::Tcp.into());
1745        assert_eq!(packet.proto(), IpProto::Tcp.into());
1746        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1747        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1748        assert_eq!(packet.body(), []);
1749    }
1750
1751    #[test]
1752    fn test_parse_with_ext_hdrs() {
1753        #[rustfmt::skip]
1754        let mut buf = [
1755            // FixedHeader (will be replaced later)
1756            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1757            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1758
1759            // HopByHop Options Extension Header
1760            Ipv6ExtHdrType::Routing.into(), // Next Header
1761            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1762            0,                       // Pad1
1763            1, 0,                    // Pad2
1764            1, 1, 0,                 // Pad3
1765
1766            // Routing Extension Header
1767            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
1768            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1769            0,                                  // Routing Type (Deprecated as per RFC 5095)
1770            0,                                  // Segments Left
1771            0, 0, 0, 0,                         // Reserved
1772            // Addresses for Routing Header w/ Type 0
1773            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1774            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1775
1776            // Destination Options Extension Header
1777            IpProto::Tcp.into(),    // Next Header
1778            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1779            0,                      // Pad1
1780            1, 0,                   // Pad2
1781            1, 1, 0,                // Pad3
1782            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
1783
1784            // Body
1785            1, 2, 3, 4, 5,
1786        ];
1787        let mut fixed_hdr = new_fixed_hdr();
1788        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1789        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1790        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1791        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1792        let mut buf = &buf[..];
1793        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1794        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1795        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1796        assert_eq!(packet.flowlabel(), 0x77);
1797        assert_eq!(packet.hop_limit(), 64);
1798        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1799        assert_eq!(packet.proto(), IpProto::Tcp.into());
1800        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1801        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1802        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1803        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1804        assert_eq!(ext_hdrs.len(), 3);
1805        // Check first extension header (hop-by-hop options)
1806        if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1807            // Everything should have been a NOP/ignore
1808            assert_eq!(options.iter().count(), 0);
1809        } else {
1810            panic!("Should have matched HopByHopOptions!");
1811        }
1812
1813        // Check second extension header (routing)
1814        if let Ipv6ExtensionHeader::Routing { routing_data } = &ext_hdrs[1] {
1815            assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1816            assert_eq!(routing_data.segments_left(), 0);
1817        } else {
1818            panic!("Should have matched RoutingExtensionHeader: {:?}", &ext_hdrs[1]);
1819        }
1820
1821        // Check the third extension header (destination options)
1822        if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[2] {
1823            // Everything should have been a NOP/ignore
1824            assert_eq!(options.iter().count(), 0);
1825        } else {
1826            panic!("Should have matched DestinationOptions!");
1827        }
1828
1829        // Test with a NoNextHeader as the final Next Header
1830        #[rustfmt::skip]
1831        let mut buf = [
1832            // FixedHeader (will be replaced later)
1833            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1834            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1835
1836            // HopByHop Options Extension Header w/ NoNextHeader as the next header
1837            Ipv6Proto::NoNextHeader.into(), // Next Header
1838            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1839            0,                       // Pad1
1840            1, 0,                    // Pad2
1841            1, 1, 0,                 // Pad3
1842
1843            // Body
1844            1, 2, 3, 4, 5,
1845        ];
1846        let mut fixed_hdr = new_fixed_hdr();
1847        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1848        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1849        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1850        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1851        let mut buf = &buf[..];
1852        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1853        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1854        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1855        assert_eq!(packet.flowlabel(), 0x77);
1856        assert_eq!(packet.hop_limit(), 64);
1857        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1858        assert_eq!(packet.proto(), Ipv6Proto::NoNextHeader);
1859        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1860        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1861        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1862        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1863        assert_eq!(ext_hdrs.len(), 1);
1864        // Check first extension header (hop-by-hop options)
1865        if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1866            // Everything should have been a NOP/ignore
1867            assert_eq!(options.iter().count(), 0);
1868        } else {
1869            panic!("Should have matched HopByHopOptions!");
1870        }
1871    }
1872
1873    #[test]
1874    fn test_parse_error() {
1875        // Set the version to 5. The version must be 6.
1876        let mut fixed_hdr = new_fixed_hdr();
1877        fixed_hdr.version_tc_flowlabel[0] = 0x50;
1878        assert_eq!(
1879            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1880            ParseError::Format.into()
1881        );
1882
1883        // Set the payload len to 2, even though there's no payload.
1884        let mut fixed_hdr = new_fixed_hdr();
1885        fixed_hdr.payload_len = U16::new(2);
1886        assert_eq!(
1887            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1888            ParseError::Format.into()
1889        );
1890
1891        // Use invalid next header.
1892        let mut fixed_hdr = new_fixed_hdr();
1893        fixed_hdr.next_hdr = 255;
1894        let packet = fixed_hdr_to_bytes(fixed_hdr);
1895
1896        // Raw parsing should succeed even with unrecognized Next Header.
1897        assert!((&packet[..]).parse::<Ipv6PacketRaw<_>>().is_ok());
1898
1899        // Full parse should fail with unrecognized next header error.
1900        assert_eq!(
1901            (&packet[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1902            Ipv6ParseError::ParameterProblem {
1903                src_ip: DEFAULT_SRC_IP,
1904                dst_ip: DEFAULT_DST_IP,
1905                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1906                pointer: u32::from(NEXT_HEADER_OFFSET),
1907                must_send_icmp: false,
1908                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1909            }
1910        );
1911
1912        // Use ICMP(v4) as next header.
1913        let mut fixed_hdr = new_fixed_hdr();
1914        fixed_hdr.next_hdr = Ipv4Proto::Icmp.into();
1915        assert_eq!(
1916            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1917            Ipv6ParseError::ParameterProblem {
1918                src_ip: DEFAULT_SRC_IP,
1919                dst_ip: DEFAULT_DST_IP,
1920                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1921                pointer: u32::from(NEXT_HEADER_OFFSET),
1922                must_send_icmp: false,
1923                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1924            }
1925        );
1926
1927        // Test HopByHop extension header not being the very first extension header
1928        #[rustfmt::skip]
1929        let mut buf = [
1930            // FixedHeader (will be replaced later)
1931            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1932            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1933
1934            // Routing Extension Header
1935            Ipv6ExtHdrType::HopByHopOptions.into(),    // Next Header (Valid but HopByHop restricted to first extension header)
1936            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1937            0,                                  // Routing Type
1938            0,                                  // Segments Left
1939            0, 0, 0, 0,                         // Reserved
1940            // Addresses for Routing Header w/ Type 0
1941            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1942            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1943
1944            // HopByHop Options Extension Header
1945            IpProto::Tcp.into(),             // Next Header
1946            0,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1947            0,                                  // Pad1
1948            1, 0,                               // Pad2
1949            1, 1, 0,                            // Pad3
1950
1951            // Body
1952            1, 2, 3, 4, 5,
1953        ];
1954        let mut fixed_hdr = new_fixed_hdr();
1955        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
1956        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1957        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1958        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1959        let mut buf = &buf[..];
1960        assert_eq!(
1961            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
1962            Ipv6ParseError::ParameterProblem {
1963                src_ip: DEFAULT_SRC_IP,
1964                dst_ip: DEFAULT_DST_IP,
1965                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1966                pointer: IPV6_FIXED_HDR_LEN as u32,
1967                must_send_icmp: false,
1968                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1969            }
1970        );
1971
1972        // Test Unrecognized Routing Type
1973        #[rustfmt::skip]
1974        let mut buf = [
1975            // FixedHeader (will be replaced later)
1976            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1977            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1978
1979            // Routing Extension Header
1980            IpProto::Tcp.into(),                // Next Header
1981            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1982            255,                                // Routing Type (Invalid)
1983            1,                                  // Segments Left
1984            0, 0, 0, 0,                         // Reserved
1985            // Addresses for Routing Header w/ Type 0
1986            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1987            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1988
1989            // Body
1990            1, 2, 3, 4, 5,
1991        ];
1992        let mut fixed_hdr = new_fixed_hdr();
1993        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
1994        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1995        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1996        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1997        let expected_error = Ipv6ParseError::ParameterProblem {
1998            src_ip: DEFAULT_SRC_IP,
1999            dst_ip: DEFAULT_DST_IP,
2000            code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
2001            pointer: (IPV6_FIXED_HDR_LEN as u32) + 2,
2002            must_send_icmp: true,
2003            action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2004        };
2005        assert_eq!((&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(), expected_error);
2006
2007        // Test an unrecognized Routing Type with an unrecognized Next Header.
2008        // This shouldn't change the result: each header should be processed
2009        // before validating the Next Header field.
2010        buf[IPV6_FIXED_HDR_LEN] = 250; // Next Header (Invalid)
2011
2012        assert_eq!((&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(), expected_error);
2013    }
2014
2015    #[test]
2016    fn test_parse_all_next_header_values() {
2017        // Test that, when parsing a packet with the fixed header's Next Header
2018        // field set to any value, parsing does not panic. A previous version
2019        // of this code would panic on some Next Header values.
2020
2021        // This packet was found via fuzzing to trigger a panic.
2022        let mut buf = [
2023            0x81, 0x13, 0x27, 0xeb, 0x75, 0x92, 0x33, 0x89, 0x01, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
2024            0x03, 0x70, 0x00, 0x22, 0xf7, 0x30, 0x2c, 0x06, 0xfe, 0xc9, 0x00, 0x2d, 0x3b, 0xeb,
2025            0xad, 0x3e, 0x5c, 0x41, 0xc8, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x11, 0x00,
2026            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x6f, 0x4f, 0x4f, 0x4f, 0x4f,
2027            0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x19, 0x19,
2028            0x19, 0x19, 0x19, 0x4f, 0x4f, 0x4f, 0x4f, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2029            0x00, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0xc9, 0x5a, 0x46, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
2030            0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0xe4, 0x5a, 0x5a, 0x5a, 0x5a,
2031        ];
2032
2033        // First, assert that the Next Header value found by the fuzzer (51)
2034        // produces the error we expect.
2035        assert_matches!(
2036            (&buf[..]).parse::<Ipv6Packet<_>>(),
2037            Err(Ipv6ParseError::ParameterProblem {
2038                src_ip: _,
2039                dst_ip: _,
2040                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2041                pointer: 6,
2042                must_send_icmp: false,
2043                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2044            })
2045        );
2046
2047        // Second, ensure that, regardless of the exact result produced, no Next
2048        // Header value causes parsing to panic.
2049        for b in 0u8..=255 {
2050            // Overwrite the Next Header field.
2051            buf[6] = b;
2052            let _: Result<_, _> = (&buf[..]).parse::<Ipv6Packet<_>>();
2053        }
2054    }
2055
2056    #[test]
2057    fn test_esp_packet() {
2058        // Encapsulating Security Payload (ESP) is not supported yet. Verify
2059        // that for ESP packets Ipv6Packet parsing fails, but Ipv6PacketRaw
2060        // parser succeeds.
2061
2062        const ESP_NEXT_HEADER: u8 = 50;
2063
2064        // 1. ESP as first extension header (Next Header in Fixed Header = ESP)
2065        let mut fixed_hdr = new_fixed_hdr();
2066        fixed_hdr.next_hdr = ESP_NEXT_HEADER;
2067        fixed_hdr.payload_len = U16::new(8);
2068        let mut buf = fixed_hdr_to_bytes(fixed_hdr).to_vec();
2069        buf.extend_from_slice(&[0; 8]);
2070
2071        // Ipv6Packet parsing fails.
2072        assert_matches!(
2073            (&buf[..]).parse::<Ipv6Packet<_>>(),
2074            Err(Ipv6ParseError::ParameterProblem {
2075                src_ip: _,
2076                dst_ip: _,
2077                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2078                pointer: 6, // Next Header field in Fixed Header.
2079                must_send_icmp: false,
2080                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2081            })
2082        );
2083
2084        // Ipv6PacketRaw parsing succeeds
2085        let mut buf_ref = &buf[..];
2086        assert!(buf_ref.parse::<Ipv6PacketRaw<_>>().is_ok());
2087
2088        // 2. ESP in middle (after Hop-by-Hop)
2089        let mut fixed_hdr = new_fixed_hdr();
2090        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2091        fixed_hdr.payload_len = U16::new(16);
2092        let mut buf = fixed_hdr_to_bytes(fixed_hdr).to_vec();
2093        // Hop-by-Hop header: Next Header = ESP (50), Hdr Ext Len = 0 (8 bytes total)
2094        buf.extend_from_slice(&[ESP_NEXT_HEADER, 0, 0, 0, 0, 0, 0, 0]);
2095        // ESP body
2096        buf.extend_from_slice(&[0; 8]);
2097
2098        // Ipv6Packet parsing fails
2099        assert_matches!(
2100            (&buf[..]).parse::<Ipv6Packet<_>>(),
2101            Err(Ipv6ParseError::ParameterProblem {
2102                src_ip: _,
2103                dst_ip: _,
2104                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2105                pointer: 40, // Next Header in the Hop-by-Hop header.
2106                must_send_icmp: false,
2107                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2108            })
2109        );
2110
2111        // Ipv6PacketRaw parsing succeeds
2112        let mut buf_ref = &buf[..];
2113        assert!(buf_ref.parse::<Ipv6PacketRaw<_>>().is_ok());
2114    }
2115
2116    #[test]
2117    fn test_parse_ext_hdr_unrecognized_next_header() {
2118        // Test that parsing an IPv6 packet with an unrecognized Next Header value
2119        // in an extension header succeeds for Ipv6PacketRaw, but fails for Ipv6Packet.
2120
2121        #[rustfmt::skip]
2122        let mut buf = [
2123            // FixedHeader (will be replaced later)
2124            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2125            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2126
2127            // HopByHop Options Extension Header
2128            250,                     // Next Header (unrecognized next header type)
2129            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2130            0,                       // Pad1
2131            1, 0,                    // Pad2
2132            1, 1, 0,                 // Pad3
2133
2134            // Body
2135            1, 2, 3, 4, 5,
2136        ];
2137        let mut fixed_hdr = new_fixed_hdr();
2138        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2139        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2140        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2141        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2142
2143        // Raw parsing should succeed.
2144        assert!((&buf[..]).parse::<Ipv6PacketRaw<_>>().is_ok());
2145
2146        // Full packet validation should fail.
2147        assert_eq!(
2148            (&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2149            Ipv6ParseError::ParameterProblem {
2150                src_ip: DEFAULT_SRC_IP,
2151                dst_ip: DEFAULT_DST_IP,
2152                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2153                pointer: IPV6_FIXED_HDR_LEN as u32,
2154                must_send_icmp: false,
2155                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2156            }
2157        );
2158    }
2159
2160    #[test]
2161    fn test_partial_parse() {
2162        use core::convert::TryInto as _;
2163        use core::ops::Deref as _;
2164
2165        // Can't partial parse extension headers:
2166        #[rustfmt::skip]
2167        let mut buf = [
2168            // FixedHeader (will be replaced later)
2169            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2170            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2171
2172            // HopByHop Options Extension Header
2173            IpProto::Tcp.into(), // Next Header
2174            0,                   // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2175            0,                   // Pad1
2176            1, 0,                // Pad2
2177            1, 1, 0,             // Pad3
2178
2179            // Body
2180            1, 2, 3, 4, 5,
2181        ];
2182        let len = buf.len() - IPV6_FIXED_HDR_LEN;
2183        let len = len.try_into().unwrap();
2184        let make_fixed_hdr = || {
2185            let mut fixed_hdr = new_fixed_hdr();
2186            fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2187            fixed_hdr.payload_len = U16::new(len);
2188            fixed_hdr
2189        };
2190        // make HopByHop malformed:
2191        const MALFORMED_BYTE: u8 = 10;
2192        buf[IPV6_FIXED_HDR_LEN + 1] = MALFORMED_BYTE;
2193        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2194        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2195        let mut buf = &buf[..];
2196        let partial = buf.parse::<Ipv6PacketRaw<_>>().unwrap();
2197        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2198        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2199        let b = extension_hdrs.as_ref().incomplete().unwrap();
2200        assert_eq!(*b, &[IpProto::Tcp.into(), MALFORMED_BYTE][..]);
2201        assert_eq!(body_proto, &Err(ExtHdrParseError));
2202        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2203
2204        // Incomplete body:
2205        let mut buf = [
2206            // FixedHeader (will be replaced later)
2207            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2208            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Body
2209            1, 2, 3, 4, 5,
2210        ];
2211        let make_fixed_hdr = || {
2212            let mut fixed_hdr = new_fixed_hdr();
2213            fixed_hdr.next_hdr = IpProto::Tcp.into();
2214            fixed_hdr.payload_len = U16::new(10);
2215            fixed_hdr
2216        };
2217        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2218        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2219        let mut parsebuff = &buf[..];
2220        let partial = parsebuff.parse::<Ipv6PacketRaw<_>>().unwrap();
2221        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2222        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2223        assert_eq!(extension_hdrs.as_ref().complete().unwrap().deref(), []);
2224        let (body, proto) = body_proto.unwrap();
2225        assert_eq!(body.incomplete().unwrap(), &buf[IPV6_FIXED_HDR_LEN..]);
2226        assert_eq!(proto, IpProto::Tcp.into());
2227        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2228    }
2229
2230    // Return a stock Ipv6PacketBuilder with reasonable default values.
2231    fn new_builder() -> Ipv6PacketBuilder {
2232        Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
2233    }
2234
2235    #[test]
2236    fn test_serialize() {
2237        let mut builder = new_builder();
2238        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2239        builder.flowlabel(0x10405);
2240        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2241            .into_serializer()
2242            .wrap_in(builder)
2243            .serialize_vec_outer(&mut NoOpSerializationContext)
2244            .unwrap();
2245        // assert that we get the literal bytes we expected
2246        assert_eq!(
2247            buf.as_ref(),
2248            &[
2249                100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2250                16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4,
2251                5, 6, 7, 8, 9
2252            ][..],
2253        );
2254
2255        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2256        // assert that when we parse those bytes, we get the values we set in
2257        // the builder
2258        assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
2259        assert_eq!(packet.dscp_and_ecn().ecn(), 3);
2260        assert_eq!(packet.flowlabel(), 0x10405);
2261    }
2262
2263    #[test]
2264    fn test_partial_serialize() {
2265        let mut builder = new_builder();
2266        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2267        builder.flowlabel(0x10405);
2268        const BODY: &[u8] = &[0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2269        let packet = (&BODY).into_serializer().wrap_in(builder);
2270
2271        // Note that this header is different from the one in test_serialize
2272        // because the checksum is not calculated.
2273        const HEADER: &[u8] = &[
2274            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
2275            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
2276        ];
2277        const PACKET_SIZE: usize = HEADER.len() + BODY.len();
2278
2279        // PartialSerializer serializes the header only if the buffer is
2280        // large enough to fit the whole header.
2281        let buf = assert_matches!(
2282            packet.partial_serialize(&mut NoOpSerializationContext, packet::new_buf_vec),
2283            Ok(PartialSerializeResult::NewBuffer { buffer, total_size: PACKET_SIZE }) => buffer
2284        );
2285        assert_eq!(buf.as_ref(), HEADER);
2286    }
2287
2288    #[test]
2289    fn test_serialize_zeroes() {
2290        // Test that Ipv6PacketBuilder::serialize properly zeroes memory before
2291        // serializing the header.
2292        let mut buf_0 = [0; IPV6_FIXED_HDR_LEN];
2293        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV6_FIXED_HDR_LEN..)
2294            .wrap_in(new_builder())
2295            .serialize_vec_outer(&mut NoOpSerializationContext)
2296            .unwrap()
2297            .unwrap_a();
2298        let mut buf_1 = [0xFF; IPV6_FIXED_HDR_LEN];
2299        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV6_FIXED_HDR_LEN..)
2300            .wrap_in(new_builder())
2301            .serialize_vec_outer(&mut NoOpSerializationContext)
2302            .unwrap()
2303            .unwrap_a();
2304        assert_eq!(&buf_0[..], &buf_1[..]);
2305    }
2306
2307    #[test]
2308    fn test_packet_builder_proto_not_next_header() {
2309        // Test that Ipv6PacketBuilder's `proto` field is used as the Protocol
2310        // Number for the upper layer payload, not the Next Header value for the
2311        // extension header.
2312        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2313            .into_serializer()
2314            .wrap_in(
2315                Ipv6PacketBuilderWithHbhOptions::new(
2316                    new_builder(),
2317                    &[HopByHopOption {
2318                        action: ExtensionHeaderOptionAction::SkipAndContinue,
2319                        mutable: false,
2320                        data: HopByHopOptionData::RouterAlert { data: 0 },
2321                    }],
2322                )
2323                .unwrap(),
2324            )
2325            .serialize_vec_outer(&mut NoOpSerializationContext)
2326            .unwrap();
2327        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2328        assert_eq!(packet.proto(), IpProto::Tcp.into());
2329        assert_eq!(packet.next_header(), Ipv6ExtHdrType::HopByHopOptions.into());
2330    }
2331
2332    #[test]
2333    #[should_panic(expected = "SizeLimitExceeded, Nested { inner: Buf { buf:")]
2334    fn test_serialize_panic_packet_length() {
2335        // Test that a packet whose payload is longer than 2^16 - 1 bytes is
2336        // rejected.
2337        let _: Buf<&mut [u8]> = Buf::new(&mut [0; 1 << 16][..], ..)
2338            .wrap_in(new_builder())
2339            .serialize_vec_outer(&mut NoOpSerializationContext)
2340            .unwrap()
2341            .unwrap_a();
2342    }
2343
2344    #[test]
2345    #[should_panic(expected = "packet must have at least one extension header")]
2346    fn test_copy_header_bytes_for_fragment_without_ext_hdrs() {
2347        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
2348        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2349        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2350    }
2351
2352    #[test]
2353    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2354    fn test_copy_header_bytes_for_fragment_with_1_ext_hdr_no_fragment() {
2355        #[rustfmt::skip]
2356        let mut buf = [
2357            // FixedHeader (will be replaced later)
2358            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2359            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2360
2361            // HopByHop Options Extension Header
2362            IpProto::Tcp.into(),     // Next Header
2363            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2364            0,                       // Pad1
2365            1, 0,                    // Pad2
2366            1, 1, 0,                 // Pad3
2367
2368            // Body
2369            1, 2, 3, 4, 5,
2370        ];
2371        let mut fixed_hdr = new_fixed_hdr();
2372        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2373        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2374        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2375        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2376        let mut buf = &buf[..];
2377        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2378        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2379    }
2380
2381    #[test]
2382    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2383    fn test_copy_header_bytes_for_fragment_with_2_ext_hdr_no_fragment() {
2384        #[rustfmt::skip]
2385        let mut buf = [
2386            // FixedHeader (will be replaced later)
2387            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2388            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2389
2390            // HopByHop Options Extension Header
2391            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2392            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2393            0,                       // Pad1
2394            1, 0,                    // Pad2
2395            1, 1, 0,                 // Pad3
2396
2397            // Destination Options Extension Header
2398            IpProto::Tcp.into(),    // Next Header
2399            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2400            0,                      // Pad1
2401            1, 0,                   // Pad2
2402            1, 1, 0,                // Pad3
2403            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2404
2405            // Body
2406            1, 2, 3, 4, 5,
2407        ];
2408        let mut fixed_hdr = new_fixed_hdr();
2409        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2410        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2411        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2412        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2413        let mut buf = &buf[..];
2414        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2415        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2416    }
2417
2418    #[test]
2419    fn test_copy_header_bytes_for_fragment() {
2420        //
2421        // Only a fragment extension header
2422        //
2423
2424        #[rustfmt::skip]
2425        let mut bytes = [
2426            // FixedHeader (will be replaced later)
2427            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2428            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2429
2430            // Fragment Extension Header
2431            IpProto::Tcp.into(),     // Next Header
2432            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2433            0, 0,                    // Fragment Offset, Res, M (M_flag)
2434            1, 1, 1, 1,              // Identification
2435
2436            // Body
2437            1, 2, 3, 4, 5,
2438        ];
2439        let mut fixed_hdr = new_fixed_hdr();
2440        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2441        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2442        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2443        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2444        let mut buf = &bytes[..];
2445        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2446        let copied_bytes = packet.copy_header_bytes_for_fragment();
2447        bytes[6] = IpProto::Tcp.into();
2448        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN]);
2449
2450        //
2451        // Fragment header after a single extension header
2452        //
2453
2454        #[rustfmt::skip]
2455        let mut bytes = [
2456            // FixedHeader (will be replaced later)
2457            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2458            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2459
2460            // HopByHop Options Extension Header
2461            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2462            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2463            0,                       // Pad1
2464            1, 0,                    // Pad2
2465            1, 1, 0,                 // Pad3
2466
2467            // Fragment Extension Header
2468            IpProto::Tcp.into(),     // Next Header
2469            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2470            0, 0,                    // Fragment Offset, Res, M (M_flag)
2471            1, 1, 1, 1,              // Identification
2472
2473            // Body
2474            1, 2, 3, 4, 5,
2475        ];
2476        let mut fixed_hdr = new_fixed_hdr();
2477        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2478        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2479        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2480        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2481        let mut buf = &bytes[..];
2482        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2483        let copied_bytes = packet.copy_header_bytes_for_fragment();
2484        bytes[IPV6_FIXED_HDR_LEN] = IpProto::Tcp.into();
2485        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 8]);
2486
2487        //
2488        // Fragment header after many extension headers (many = 2)
2489        //
2490
2491        #[rustfmt::skip]
2492        let mut bytes = [
2493            // FixedHeader (will be replaced later)
2494            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2495            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2496
2497            // HopByHop Options Extension Header
2498            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2499            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2500            0,                       // Pad1
2501            1, 0,                    // Pad2
2502            1, 1, 0,                 // Pad3
2503
2504            // Destination Options Extension Header
2505            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2506            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2507            0,                      // Pad1
2508            1, 0,                   // Pad2
2509            1, 1, 0,                // Pad3
2510            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2511
2512            // Fragment Extension Header
2513            IpProto::Tcp.into(),     // Next Header
2514            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2515            0, 0,                    // Fragment Offset, Res, M (M_flag)
2516            1, 1, 1, 1,              // Identification
2517
2518            // Body
2519            1, 2, 3, 4, 5,
2520        ];
2521        let mut fixed_hdr = new_fixed_hdr();
2522        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2523        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2524        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2525        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2526        let mut buf = &bytes[..];
2527        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2528        let copied_bytes = packet.copy_header_bytes_for_fragment();
2529        bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2530        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 24]);
2531
2532        //
2533        // Fragment header before an extension header
2534        //
2535
2536        #[rustfmt::skip]
2537        let mut bytes = [
2538            // FixedHeader (will be replaced later)
2539            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2540            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2541
2542            // Fragment Extension Header
2543            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2544            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2545            0, 0,                    // Fragment Offset, Res, M (M_flag)
2546            1, 1, 1, 1,              // Identification
2547
2548            // Destination Options Extension Header
2549            IpProto::Tcp.into(),    // Next Header
2550            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2551            0,                      // Pad1
2552            1, 0,                   // Pad2
2553            1, 1, 0,                // Pad3
2554            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2555
2556            // Body
2557            1, 2, 3, 4, 5,
2558        ];
2559        let mut fixed_hdr = new_fixed_hdr();
2560        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2561        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2562        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2563        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2564        let mut buf = &bytes[..];
2565        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2566        let copied_bytes = packet.copy_header_bytes_for_fragment();
2567        let mut expected_bytes = Vec::new();
2568        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2569        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2570        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2571        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2572
2573        //
2574        // Fragment header before many extension headers (many = 2)
2575        //
2576
2577        #[rustfmt::skip]
2578        let mut bytes = [
2579            // FixedHeader (will be replaced later)
2580            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2581            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2582
2583            // Fragment Extension Header
2584            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2585            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2586            0, 0,                    // Fragment Offset, Res, M (M_flag)
2587            1, 1, 1, 1,              // Identification
2588
2589            // Destination Options Extension Header
2590            Ipv6ExtHdrType::Routing.into(),    // Next Header
2591            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2592            0,                      // Pad1
2593            1, 0,                   // Pad2
2594            1, 1, 0,                // Pad3
2595            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2596
2597            // Routing extension header
2598            IpProto::Tcp.into(),                // Next Header
2599            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2600            0,                                  // Routing Type (Deprecated as per RFC 5095)
2601            0,                                  // Segments Left
2602            0, 0, 0, 0,                         // Reserved
2603            // Addresses for Routing Header w/ Type 0
2604            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2605            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2606
2607            // Body
2608            1, 2, 3, 4, 5,
2609        ];
2610        let mut fixed_hdr = new_fixed_hdr();
2611        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2612        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2613        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2614        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2615        let mut buf = &bytes[..];
2616        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2617        let copied_bytes = packet.copy_header_bytes_for_fragment();
2618        let mut expected_bytes = Vec::new();
2619        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2620        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2621        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2622        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2623
2624        //
2625        // Fragment header between extension headers
2626        //
2627
2628        #[rustfmt::skip]
2629        let mut bytes = [
2630            // FixedHeader (will be replaced later)
2631            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2632            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2633
2634            // HopByHop Options Extension Header
2635            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2636            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2637            0,                       // Pad1
2638            1, 0,                    // Pad2
2639            1, 1, 0,                 // Pad3
2640
2641            // Fragment Extension Header
2642            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2643            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2644            0, 0,                    // Fragment Offset, Res, M (M_flag)
2645            1, 1, 1, 1,              // Identification
2646
2647            // Destination Options Extension Header
2648            IpProto::Tcp.into(),    // Next Header
2649            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2650            0,                      // Pad1
2651            1, 0,                   // Pad2
2652            1, 1, 0,                // Pad3
2653            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2654
2655            // Body
2656            1, 2, 3, 4, 5,
2657        ];
2658        let mut fixed_hdr = new_fixed_hdr();
2659        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2660        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2661        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2662        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2663        let mut buf = &bytes[..];
2664        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2665        let copied_bytes = packet.copy_header_bytes_for_fragment();
2666        let mut expected_bytes = Vec::new();
2667        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 8]);
2668        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 16..bytes.len() - 5]);
2669        expected_bytes[IPV6_FIXED_HDR_LEN] = Ipv6ExtHdrType::DestinationOptions.into();
2670        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2671
2672        //
2673        // Multiple fragment extension headers
2674        //
2675
2676        #[rustfmt::skip]
2677        let mut bytes = [
2678            // FixedHeader (will be replaced later)
2679            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2680            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2681
2682            // Fragment Extension Header
2683            Ipv6ExtHdrType::Fragment.into(),     // Next Header
2684            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2685            0, 0,                    // Fragment Offset, Res, M (M_flag)
2686            1, 1, 1, 1,              // Identification
2687
2688            // Fragment Extension Header
2689            IpProto::Tcp.into(),     // Next Header
2690            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2691            0, 0,                    // Fragment Offset, Res, M (M_flag)
2692            2, 2, 2, 2,              // Identification
2693
2694            // Body
2695            1, 2, 3, 4, 5,
2696        ];
2697        let mut fixed_hdr = new_fixed_hdr();
2698        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2699        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2700        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2701        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2702        let mut buf = &bytes[..];
2703        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2704        let copied_bytes = packet.copy_header_bytes_for_fragment();
2705        let mut expected_bytes = Vec::new();
2706        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2707        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2708        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2709
2710        //
2711        // Fragment header immediately following Routing header.
2712        // Regression test for https://fxbug.dev/517297331.
2713        //
2714
2715        #[rustfmt::skip]
2716        let mut bytes = [
2717            // FixedHeader (will be replaced later)
2718            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2719            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2720
2721            // HopByHop Options Extension Header
2722            Ipv6ExtHdrType::Routing.into(), // Next Header (Routing)
2723            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2724            0,                       // Pad1
2725            1, 0,                    // Pad2
2726            1, 1, 0,                 // Pad3
2727
2728            // Routing extension header
2729            Ipv6ExtHdrType::Fragment.into(), // Next Header (Fragment)
2730            4,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2731            0,                       // Routing Type
2732            0,                       // Segments Left
2733            0, 0, 0, 0,              // Reserved
2734            // Addresses for Routing Header w/ Type 0
2735            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2736            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2737
2738            // Fragment Extension Header
2739            IpProto::Tcp.into(),     // Next Header (TCP)
2740            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2741            0, 0,                    // Fragment Offset, Res, M (M_flag)
2742            1, 1, 1, 1,              // Identification
2743
2744            // Body (TCP packet mock bytes)
2745            1, 2, 3, 4, 5,
2746        ];
2747        let mut fixed_hdr = new_fixed_hdr();
2748        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2749        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2750        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2751        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2752        let mut buf = &bytes[..];
2753        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2754        let copied_bytes = packet.copy_header_bytes_for_fragment();
2755        let mut expected_bytes = Vec::new();
2756        // 8 (HopByHop) + (8 + 16 + 16) (Routing).
2757        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 48]);
2758        expected_bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2759        assert_eq!(copied_bytes, expected_bytes);
2760    }
2761
2762    #[test]
2763    fn test_next_multiple_of_eight() {
2764        for x in 0usize..=IPV6_HBH_OPTIONS_MAX_LEN {
2765            let y = next_multiple_of_eight(x);
2766            assert_eq!(y % 8, 0);
2767            assert!(y >= x);
2768            if x % 8 == 0 {
2769                assert_eq!(x, y);
2770            } else {
2771                assert_eq!(x + (8 - x % 8), y);
2772            }
2773        }
2774    }
2775
2776    fn create_ipv4_and_ipv6_builders(
2777        proto_v4: Ipv4Proto,
2778        proto_v6: Ipv6Proto,
2779    ) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
2780        const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
2781        const IP_TTL: u8 = 64;
2782
2783        let mut ipv4_builder =
2784            Ipv4PacketBuilder::new(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP, IP_TTL, proto_v4);
2785        ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
2786        ipv4_builder.df_flag(false);
2787        ipv4_builder.mf_flag(false);
2788        ipv4_builder.fragment_offset(FragmentOffset::ZERO);
2789
2790        let mut ipv6_builder =
2791            Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v6);
2792        ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
2793        ipv6_builder.flowlabel(0x456);
2794
2795        (ipv4_builder, ipv6_builder)
2796    }
2797
2798    fn create_tcp_ipv4_and_ipv6_pkt()
2799    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
2800        use crate::tcp::TcpSegmentBuilder;
2801        use core::num::NonZeroU16;
2802
2803        let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
2804        let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
2805        const TCP_SEQ_NUM: u32 = 4321;
2806        const TCP_ACK_NUM: Option<u32> = Some(1234);
2807        const TCP_WINDOW_SIZE: u16 = 12345;
2808        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2809
2810        let (ipv4_builder, ipv6_builder) =
2811            create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
2812
2813        let tcp_builder = TcpSegmentBuilder::new(
2814            DEFAULT_V4_SRC_IP,
2815            DEFAULT_V4_DST_IP,
2816            tcp_src_port,
2817            tcp_dst_port,
2818            TCP_SEQ_NUM,
2819            TCP_ACK_NUM,
2820            TCP_WINDOW_SIZE,
2821        );
2822
2823        let v4_pkt_buf = (&PAYLOAD)
2824            .into_serializer()
2825            .wrap_in(tcp_builder)
2826            .wrap_in(ipv4_builder)
2827            .serialize_vec_outer(&mut NoOpSerializationContext)
2828            .expect("Failed to serialize to v4_pkt_buf");
2829
2830        let v6_tcp_builder = TcpSegmentBuilder::new(
2831            DEFAULT_SRC_IP,
2832            DEFAULT_DST_IP,
2833            tcp_src_port,
2834            tcp_dst_port,
2835            TCP_SEQ_NUM,
2836            TCP_ACK_NUM,
2837            TCP_WINDOW_SIZE,
2838        );
2839
2840        let v6_pkt_buf = (&PAYLOAD)
2841            .into_serializer()
2842            .wrap_in(v6_tcp_builder)
2843            .wrap_in(ipv6_builder)
2844            .serialize_vec_outer(&mut NoOpSerializationContext)
2845            .expect("Failed to serialize to v4_pkt_buf");
2846
2847        (v4_pkt_buf, v6_pkt_buf)
2848    }
2849
2850    #[test]
2851    fn test_nat64_translate_tcp() {
2852        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
2853
2854        let parsed_v6_packet =
2855            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Failed to parse v6_pkt_buf");
2856        let nat64_translation_result =
2857            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2858
2859        let serializable_pkt =
2860            assert_matches!(nat64_translation_result, Nat64TranslationResult::Forward(s) => s);
2861
2862        let translated_v4_pkt_buf = serializable_pkt
2863            .serialize_vec_outer(&mut NoOpSerializationContext)
2864            .expect("Failed to serialize to translated_v4_pkt_buf");
2865
2866        assert_eq!(
2867            expected_v4_pkt_buf.to_flattened_vec(),
2868            translated_v4_pkt_buf.to_flattened_vec()
2869        );
2870    }
2871
2872    fn create_udp_ipv4_and_ipv6_pkt()
2873    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
2874        use crate::udp::UdpPacketBuilder;
2875        use core::num::NonZeroU16;
2876
2877        let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
2878        let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
2879        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2880
2881        let (ipv4_builder, ipv6_builder) =
2882            create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
2883
2884        let v4_udp_builder = UdpPacketBuilder::new(
2885            DEFAULT_V4_SRC_IP,
2886            DEFAULT_V4_DST_IP,
2887            Some(udp_src_port),
2888            udp_dst_port,
2889        );
2890
2891        let v4_pkt_buf = (&PAYLOAD)
2892            .into_serializer()
2893            .wrap_in(v4_udp_builder)
2894            .wrap_in(ipv4_builder)
2895            .serialize_vec_outer(&mut NoOpSerializationContext)
2896            .expect("Unable to serialize to v4_pkt_buf");
2897
2898        let v6_udp_builder =
2899            UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
2900
2901        let v6_pkt_buf = (&PAYLOAD)
2902            .into_serializer()
2903            .wrap_in(v6_udp_builder)
2904            .wrap_in(ipv6_builder)
2905            .serialize_vec_outer(&mut NoOpSerializationContext)
2906            .expect("Unable to serialize to v6_pkt_buf");
2907
2908        (v4_pkt_buf, v6_pkt_buf)
2909    }
2910
2911    #[test]
2912    fn test_nat64_translate_udp() {
2913        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
2914
2915        let parsed_v6_packet =
2916            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Unable to parse Ipv6Packet");
2917        let nat64_translation_result =
2918            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2919
2920        let serializable_pkt = assert_matches!(nat64_translation_result,
2921                                               Nat64TranslationResult::Forward(s) => s);
2922
2923        let translated_v4_pkt_buf = serializable_pkt
2924            .serialize_vec_outer(&mut NoOpSerializationContext)
2925            .expect("Unable to serialize to translated_v4_pkt_buf");
2926
2927        assert_eq!(
2928            expected_v4_pkt_buf.to_flattened_vec(),
2929            translated_v4_pkt_buf.to_flattened_vec()
2930        );
2931    }
2932
2933    #[test]
2934    fn test_nat64_translate_non_tcp_udp_icmp() {
2935        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2936
2937        let (ipv4_builder, ipv6_builder) =
2938            create_ipv4_and_ipv6_builders(Ipv4Proto::Other(59), Ipv6Proto::Other(59));
2939
2940        let expected_v4_pkt_buf = (&PAYLOAD)
2941            .into_serializer()
2942            .wrap_in(ipv4_builder)
2943            .serialize_vec_outer(&mut NoOpSerializationContext)
2944            .expect("Unable to serialize to expected_v4_pkt_buf");
2945
2946        let mut v6_pkt_buf = (&PAYLOAD)
2947            .into_serializer()
2948            .wrap_in(ipv6_builder)
2949            .serialize_vec_outer(&mut NoOpSerializationContext)
2950            .expect("Unable to serialize to v6_pkt_buf");
2951
2952        let translated_v4_pkt_buf = {
2953            let parsed_v6_packet = v6_pkt_buf
2954                .parse::<Ipv6Packet<_>>()
2955                .expect("Unable to serialize to translated_v4_pkt_buf");
2956
2957            let nat64_translation_result =
2958                parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2959
2960            let serializable_pkt = assert_matches!(nat64_translation_result,
2961                                                   Nat64TranslationResult::Forward(s) => s);
2962
2963            let translated_buf = serializable_pkt
2964                .serialize_vec_outer(&mut NoOpSerializationContext)
2965                .expect("Unable to serialize to translated_buf");
2966
2967            translated_buf
2968        };
2969
2970        assert_eq!(
2971            expected_v4_pkt_buf.to_flattened_vec(),
2972            translated_v4_pkt_buf.to_flattened_vec()
2973        );
2974    }
2975
2976    #[test_case(new_builder(), true; "fixed header more frags")]
2977    #[test_case(Ipv6PacketBuilderWithHbhOptions::new(
2978        new_builder(),
2979        &[HopByHopOption {
2980            action: ExtensionHeaderOptionAction::SkipAndContinue,
2981            mutable: false,
2982            data: HopByHopOptionData::RouterAlert { data: 0 },
2983        }]).unwrap(), false; "hbh last frag")]
2984    fn ipv6_packet_builder_with_fragment_header<
2985        B: Ipv6HeaderBuilder + Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> + Debug,
2986    >(
2987        inner: B,
2988        more_fragments: bool,
2989    ) {
2990        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2991        let fragment_offset = FragmentOffset::new(13).unwrap();
2992        let identification = 0xABCDABCD;
2993        let builder = Ipv6PacketBuilderWithFragmentHeader::new(
2994            inner,
2995            fragment_offset,
2996            more_fragments,
2997            identification,
2998        );
2999        let mut serialized = builder
3000            .wrap_body(PAYLOAD.into_serializer())
3001            .serialize_vec_outer(&mut NoOpSerializationContext)
3002            .unwrap()
3003            .unwrap_b();
3004        let packet = serialized.parse::<Ipv6Packet<_>>().unwrap();
3005        assert!(packet.fragment_header_present());
3006        assert_eq!(packet.proto(), Ipv6Proto::Proto(IpProto::Tcp));
3007        let fragment_data = packet
3008            .extension_hdrs
3009            .into_iter()
3010            .find_map(|ext_hdr| match ext_hdr {
3011                Ipv6ExtensionHeader::Fragment { fragment_data } => Some(fragment_data),
3012                _ => None,
3013            })
3014            .unwrap();
3015        assert_eq!(fragment_data.fragment_offset(), fragment_offset);
3016        assert_eq!(fragment_data.identification(), identification);
3017        assert_eq!(fragment_data.m_flag(), more_fragments);
3018    }
3019
3020    // Tests that the PacketBuilder implementations correct the maximum body
3021    // length in PacketConstraints to remove any extension header bytes used.
3022    #[test]
3023    fn extension_headers_take_from_max_body_size() {
3024        let builder = new_builder();
3025        assert_eq!(builder.constraints().max_body_len(), IPV6_MAX_PAYLOAD_LENGTH);
3026        let builder =
3027            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, 1234);
3028        assert_eq!(
3029            builder.constraints().max_body_len(),
3030            IPV6_MAX_PAYLOAD_LENGTH - IPV6_FRAGMENT_EXT_HDR_LEN
3031        );
3032    }
3033
3034    #[test]
3035    fn test_partial_serialize_parsed() {
3036        const PACKET_BYTES: &[u8] = &[
3037            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
3038            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4, 5, 6, 7,
3039            8, 9,
3040        ];
3041        const PACKET_LEN: usize = PACKET_BYTES.len();
3042        let mut packet_bytes_copy = Vec::from(PACKET_BYTES);
3043        let mut packet_bytes_ref: &mut [u8] = &mut packet_bytes_copy[..];
3044        let packet = packet_bytes_ref.parse::<Ipv6Packet<_>>().unwrap();
3045
3046        let buf = assert_matches!(
3047            packet.partial_serialize(&mut NoOpSerializationContext, packet::new_buf_vec),
3048            Ok(PartialSerializeResult::NewBuffer { buffer, total_size: PACKET_LEN }) => buffer
3049        );
3050        assert_eq!(buf.as_ref(), PACKET_BYTES);
3051    }
3052}