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